1

I am trying to compare std::thread with std::async in this small example that I came up with for a fun exercise. I generate eight vectors with ten random numbers from 0 to 1000. I then push those vectors into a queue so that I can go ahead and multithread the sorting later. Here is the function I am using to generate the random numbers:

std::vector<int> generate(int count) { std::vector<int> newVec(count); std::random_device rd; std::mt19937 mt(rd()); std::uniform_int_distribution<> dis(0,1000); std::generate(begin(newVec),end(newVec),std::bind(dis,std::ref(mt))); return newVec; } 

In my thread example, I simply lock the queue, grab a vector out of it, call std::sort on it, and push that back into a list of vectors so I can merge it into one final vector in the end. That was easy enough to implement, but I am trying to figure out how to implement this same thing with std::async This is what I have tried so far:

void work(std::deque<std::vector<int>>& queue, std::list<std::vector<int>> toMerge) { std::vector<int> temp; temp = queue.front(); auto handle = std::async(std::launch::async,sortIt,temp); queue.pop_front(); toMerge.push_back(temp); } 

I then realized, that this would not do what I thought it would. As I do not believe this could call itself over and over again. So I tried this one:

void work(std::deque<std::vector<int>>& queue, std::list<std::vector<int>> toMerge) { if(queue.empty() { return; } else { auto handle = std::async(std::launch::async[&]{return std::sort(queue.front.begin(),queue.front.end());},work,queue,toMerge); } } 

But that gave me all sorts of compiler errors that I don't really know how to tackle.

How can I achieve this task?

Full code:

void sortIt(std::vector<int>& v) { std::sort(begin(v),end(v)); } void print(std::vector<int> &v) { for(auto &&e : v) { std::cout << e << " "; } std::cout << std::endl; } std::vector<int> generate(int count) { std::vector<int> newVec(count); std::random_device rd; std::mt19937 mt(rd()); std::uniform_int_distribution<> dis(0,1000); std::generate(begin(newVec),end(newVec),std::bind(dis,std::ref(mt))); return newVec; } void work(std::deque<std::vector<int>>& queue, std::list<std::vector<int>> toMerge) { //TODO: Make asnyc work } int main() { std::deque<std::vector<int>> queue; std::vector<int> tempA; std::vector<int> tempB; std::vector<int> finalVec; std::list<std::vector<int>> toMerge; for(int i = 0; i < 8; ++i) { queue.push_back(generate(10)); } work(queue,toMerge); } 
2
  • It is unclear what you are asking. async returns future with results, you need to call get on future to wait until task ends. What is your goal? Do you want to start 8 tasks by async (each task sorts one vector) and at the end merges all sorted vector into list ? Commented Nov 21, 2018 at 8:09
  • @rafix07 yes that is exactly it. In fact, I do not need async to merge the vectors. I was going to have the program do that in the end by calling std::merge on my list of vectors using tempA, tempB, and finalVec. Commented Nov 21, 2018 at 16:16

1 Answer 1

2

All you need is to create vector for holding future objects, iterate over queue and at each iterator call async function to start asynchronous operation - in your case it is sorting of vector. For each future object you have to call get method to retrieve sorted vector. Obtained sorted vector by get is added to toMerge list.

void work( const std::deque<std::vector<int>>& queue, // const added - don't modify queue std::list<std::vector<int>>& toMerge) // pass toMerge by reference to store results { std::vector<std::future< std::vector<int> >> tasks; for (const std::vector<int>& v : queue) tasks.push_back (std::async( [vecCopy = v]() mutable { // copy v into vecCopy std::sort(vecCopy.begin(), vecCopy.end()); return vecCopy; })); // wait until all tasks are complete for (std::future< std::vector<int> >& f : tasks) toMerge.push_back(f.get()); // move vector into list } 

Lambda which sorts look like:

[vecCopy = v]() mutable { // copy v into vecCopy std::sort(vecCopy.begin(), vecCopy.end()); return vecCopy; } 

you don't want to modify v from queue hence the copy of v is made, the content of v is copied into vecCopy. Because closure keeps vecCopy by value you need to put mutable keyword to lambda to allow vecCopy to be modified.

Sign up to request clarification or add additional context in comments.

2 Comments

Wow! That was really cool! This is the solution I was looking for, the question I have for you is about vecCopy, what is going on when you call vecCopy = v? How does vecCopy know that it is a vector?
Is works since c++14, in C++11 you can pass variable into closure by reference [&v] - it doesn't work because you cannot call sort on const v, or by value [v] mutable it also doesn't work because v is const. Since C++14 you can name captured value and initialize it, vecCopy = v means that closure has vecCopy as data member and this vector is copy of v. You can google lambda capture expressions c++14 to see more details.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.