Is it safe to access a variable from the main thread after it was written to by another thread and after that thread was joined?

c++

Solution

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.

Problem

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?

Original source