Reputation: 1191
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);
}
Upvotes: 1
Views: 3725
Reputation: 20936
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.
Upvotes: 2