Last active
January 20, 2017 10:52
-
-
Save wojciak/deacea7b02e3192cf2ba6a5024d3bc85 to your computer and use it in GitHub Desktop.
Exploring how to generate multi-threaded async code in c++11/14
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#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; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
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 vectorline #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 ordinarytypedef ValueType double;
or using the newdecltype
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 functionstart