Yes, this particular piece of code is thread safe; barriers or locks are not required.
This is the timeline of events regarding your code:
thread 1 -------- | int x = 0; (write 0 to x) | std::thread thread 2 (start thread 2) --------> -------- | | join(); x = 1; (thread 1 suspended) (write 1 to x) . | . thread 2 returns . | (thread 1 resumes) <------- x | std::cout << x; (read from x) | thread 1 returns | x
As you can see, there is no way to access x more than one thread. In fact, using join() effectively makes access to x available in sequential order, you guessed it. join() provides synchronization instead of the synchronization that you get from locks.
Basically, you have an example of how you can have multithreading with zero concurrency.
Of course, this is only true because of the call to join() , which occurs immediately after creating the stream in the provided code fragment. If you had something like this:
int x = 0; std::thread t([&]{ x = 1; }); std::cout << x; t.join();
The timeline instead may look like this:
thread 1 -------- | int x = 0; (write 0 to x) | std::thread thread 2 (start thread 2) --------> -------- | | std::cout << x; x = 1; (read from x) (write 1 to x) <-- PROBLEM! | | join(); | (thread 1 suspended) | . | . thread 2 returns . | (thread 1 resumes) <------- x | thread 1 returns | x
Reordering join() in this way will result in a race.
source share