Skip to content

Instantly share code, notes, and snippets.

@wojciak
Last active January 20, 2017 10:52
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save wojciak/deacea7b02e3192cf2ba6a5024d3bc85 to your computer and use it in GitHub Desktop.
Save wojciak/deacea7b02e3192cf2ba6a5024d3bc85 to your computer and use it in GitHub Desktop.
Exploring how to generate multi-threaded async code in c++11/14
#include <thread>
#include <future>
#include <chrono>
#include <iostream>
#include <vector>
double runMeAsync(int n) {
n *= 10000000;
for (unsigned i = 0; i < 100000000; i++) {
n++;
}
return n;
}
std::future<double> start(int n) {
std::packaged_task<double(int)> task(&runMeAsync);
auto f = task.get_future();
std::thread t(std::move(task), n);
t.detach();
return f;
}
int main() {
unsigned n = 0;
short processCount = 100;
short finished = 0;
std::vector<std::future<double>> *features = new std::vector<std::future<double>>;
while (n < processCount) {
features->emplace_back(start(n));
n++;
}
while (features->size()) {
unsigned i = 0;
while (i < features->size()) {
if (features->at(i).wait_for(std::chrono::milliseconds(1000 / 60)) == std::future_status::ready) {
finished++;
std::cout << "Finished: " << finished << " with: " << features->at(i).get() << std::endl;
features->erase(features->begin() + i);
}
i++;
}
}
return 0;
}
@boba2
Copy link

boba2 commented Jan 20, 2017

line #16

auto start(int n) {...

it's generally advised to use auto more often (whenever possible)

line #31

We don't use pointers (directly) in modern C++. If you use them (*, ->) you should have a really good reason to do so. And then whenever you create a value dynamically (new) you have to dispose it later (delete) to avoid memory leaks.

This all can be avoided by creating the value statically on the stack. Simply std::vector<std::future<double>> futures;. And then access its members with the dot operator (futures.emplace_back(...)) instead of the arrow.

line #38

while (!futures.empty()) {...

line #41

for (auto& future: futures) {... and then no need to access the future by its index in the vector

line #45

never modify a collection while iterating over it

And then there is also the thing with the double type being repeated in lines 7, 16 and 31. Ideally the type should be specified only in one place so that one could change it only in this place without the need to alter many other lines of code. This could be done twofold: with a plain ordinary typedef ValueType double; or using the new decltype keyword:

you would leave the line 7 as it is now, then the line 16 would have replaced the type specification with auto and in the line 31 you would have this:

std::vector<decltype(start(0))> futures; which would effectively declare a vector of values of the same type as the one returned by the function start

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment