Std::thread::join is said to 'synchronize-with' the joined thread, however synchronization doesnt tell anything about visibility of side effects, it merely governs the order of the visiblity, ie. in following example:
int g_i = 0;
int main()
{
auto fn = [&] {g_i = 1;};
std::thread t1(fn);
t1.join();
return g_i;
}
Do we have any guarantee in the c++ standard that this program will always return 1?
It is not thread safe. If you have more than one thread that can call your snippet at any time, you may experience a race condition. The only real way to protect against this is by wrapping your snippet in an std::mutex shared by the threads calling said snippet.
std::thread::join. Blocks the current thread until the thread identified by *this finishes its execution. The completion of the thread identified by *this synchronizes with the corresponding successful return from join() .
Join is a synchronization method that blocks the calling thread (that is, the thread that calls the method) until the thread whose Join method is called has completed. Use this method to ensure that a thread has been terminated. The caller will block indefinitely if the thread does not terminate.
4) The copy constructor is deleted; threads are not copyable. No two std::thread objects may represent the same thread of execution.
[thread.thread.member]:
void join();
Effects: Blocks until the thread represented by*this
has completed.
Synchronization: The completion of the thread represented by*this
synchronizes with the corresponding successfuljoin()
return.
Since the completion of the thread execution synchronizes with the return from thread::join
, the completion of the thread inter-thread happens before the return:
An evaluation A inter-thread happens before an evaluation B if
— A synchronizes with B
and thus happens before it:
An evaluation A happens before an evaluation B (or, equivalently, B happens after A) if:
— A inter-thread happens before B
Due to (inter-thread) happens before transitivity (let me skip copypasting the whole definition of inter-thread happens before to show this), everything what happened before the completion of the thread, including the write of the value 1
into g_i
, happens before the return from thread::join
. The return from thread::join
, in turn, happens before the read of value of g_i
in return g_i;
simply because the invocation of thread::join
is sequenced before return g_i;
. Again, using the transitivity, we establish that the write of 1
to g_i
in the non-main thread happens before the read of g_i
in return g_i;
in the main thread.
Write of 1
into g_i
is visible side effect with respect to the read of g_i
in return g_i;
:
A visible side effect A on a scalar object or bit-field M with respect to a value computation B of M satisfies the conditions:
— A happens before B and
— there is no other side effect X to M such that A happens before X and X happens before B.
The value of a non-atomic scalar object or bit-field M, as determined by evaluation B, shall be the value stored by the visible side effect A.
Emphasis of the last sentence is mine and it guarantees that the value read from g_i
in return g_i;
will be 1
.
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