When I run this code:
#include <iostream>
#include <thread>
#include <mutex>
std::mutex m;
int main()
{
std::vector<std::thread> workers;
for (int i = 0; i < 10; ++i)
{
workers.emplace_back([i]
{
std::lock_guard<std::mutex> lock(m);
std::cout << "Hi from thread " << i << std::endl;
});
}
std::for_each(workers.begin(), workers.end(), [] (std::thread& t)
{ t.join(); });
}
I get the output:
Hi from thread 7
Hi from thread 1
Hi from thread 4
Hi from thread 6
Hi from thread 0
Hi from thread 5
Hi from thread 2
Hi from thread 3
Hi from thread 9
Hi from thread 8
Even though I used a mutex to keep only one thread access at a time. Why isn't the output in order?
What your mutex achieves is that no two threads print at the same time. However, they are still racing for which thread acquires the mutex first.
If you want to have serial execution you can just avoid threads at all.
It is totally up to the operating system in which order threads are scheduled. You can not rely on any order. Assume it is totally random.
You are passing a lambda to emplace_back which is used as a parameter for the std::thread constructor. See the details for emplace_back copy/pasted below from cppreference.com.
"Appends a new element to the end of the container. The element is constructed through std::allocator_traits::construct, which typically uses placement-new to construct the element in-place at the location provided by the container. The arguments args... are forwarded to the constructor as std::forward(args)...."
http://en.cppreference.com/w/cpp/container/vector/emplace_back
The mutex in the body of the lambda has no affect until the std::thread object has been fully constructed and running the thread entry point defined by the lambda body. Some of the std::threads could start running during the loop, or the threads might not start until after the loop completes. You can't figure this out in a portable way.
After the for-loop constructs all your std::threads in your vector, it is up to the OS to decide in what order the threads are scheduled to run and that is how you get the random ordering of your output.
The execution order is immaterial, you cannot predict it and it will change from run to run and over time in a given run.
Your designs should never depend on thread execution order in any way or form.
It goes further than that: if N threads are waiting on a synchronization object, say a mutex, and the mutex gets released, there is no way to reliably and portably predict which of the waiting threads will be awaken and grab the mutex next, irrespectively of their relative scheduling priorities.
Non-determinism makes multithreaded programming difficult :-)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With