Is this thread-safe?
int x = 0;
std::thread([&]{ x = 1; }).join();
std::cout << x;
Variable x is accessed from two threads without using atomics or locks. However, the call to join()
forces the accesses to x to be sequential.
Is a memory barrier required here?
A data race is a state, in which at least two threads access shared data at the same time, and at least one of the threads is a writer. A critical section is a section of the code, which not more than one thread should access at any point in time.
A race condition occurs when two threads access a shared variable at the same time. The first thread reads the variable, and the second thread reads the same value from the variable.
As long as it's a plain variable, it's no risk. If it is a property, reading it can possibly have side effects, so is not guaranteed to be thread safe. Save this answer.
Yes, that particular code snippet is thread safe; barriers or locks are not required.
This is the timeline of events with respect to 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, at no point is x
being accessed by more than one thread. In fact, the use of join()
effectively makes all accesses to x
happen in sequential order, as you've surmised. The join()
provides the synchronization in lieu of the synchronization you get from locks.
Basically, what you have is an example of how you can have multithreading with zero concurrency.
Of course, this is true only because of the call to join()
, which happens immediately after you create the thread in the code snippet you provide. If you instead had something like this:
int x = 0;
std::thread t([&]{ x = 1; });
std::cout << x;
t.join(); // Move join() call here
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
Changing the order of join()
in this manner will introduce a race.
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