Reputation: 1639
How can one in this simple example guarantee that the
a->push_back(i)
happens in the order in which the threads are started? So a contents would be {1,2,3}.
#include <vector>
#include <thread>
void do_stuf(int i,std::vector<int> * a)
{
//do very long stuff
a->push_back(i);
}
int main()
{
std::vector<int> tmp;
std::thread t1(do_stuf,1,&tmp);
std::thread t2(do_stuf,2,&tmp);
std::thread t3(do_stuf,3,&tmp);
t1.join();
t2.join();
t3.join();
}
Upvotes: 2
Views: 904
Reputation: 2555
Sorry, I've missed the "//do very long stuff". If there is a special action that have to be done in a specific order at the end of the long action, you can simply put that code behind the joining of the 3 threads.
If this actions have to be done by that specific thread, you can use a shared counter protected by a mutex and a condition variable to signal that this counter has been changed. When changing the counter, all waiters have to be notified, because a specific thread needs to be woken up. At the end of the function the function waits for the counter to have a thread specific value. The first thread is waiting for the initial value, doing it's action, incrementing the counter. The second thread is waiting for the counter to become the second value etc.
Upvotes: 0
Reputation: 68658
One way is to pass the threads a pointer or reference to the place you want them to store their result (and make sure it remains allocated for the threads lifetime), like this:
void do_stuf(int i, int* a)
{
//do very long stuff
*a = i;
}
int main()
{
std::vector<int> tmp(3);
std::thread t1(do_stuf,1,&tmp[0]);
std::thread t2(do_stuf,2,&tmp[1]);
std::thread t3(do_stuf,3,&tmp[2]);
t1.join();
t2.join();
t3.join();
}
It isn't clear from your example what you are trying to achieve, but have you had a look at std::promise and std::future and figured out what they do? They may be what you want.
(The trouble with vector::push_back in this context is that it isn't thread-safe. It may overwrite the same element if two push_backs executions overlap, or it may reallocate the array moving the storage location of all the elements.)
Upvotes: 5
Reputation: 13026
As written, the insertions can be ordered arbitrarily. To ensure you order you want, you basically need a ticketing system in which threads sleep/spin until their ticket number is requested. At a high level, that means that you pass an extra piece of information to each thread (its ticket number), have a global shared value that is the requested ticket ID, and the thread code has some code that ensures that no insertion is performed until the global ID equals the local number.
Upvotes: -1
Reputation: 10605
You could approach this a couple of ways. If you don't care what order they complete, just the order of the results, push an object with the task id and its result, then sort the object by task id and print when all are done.
If you actually want them to not report until the previous task completes, you need to wait on the previous task.
Upvotes: 0
Reputation: 299
You could have a callback that 'syncronizes' the push back when that threads long process is complete in the order that they were dispatched.
Side note, if you are wanting push_back in a multithreaded world I would use list and not vector, list will preserve the iterators for everything other than the element being deleted...
Upvotes: -1