konchy
konchy

Reputation: 861

Is it safe to read variable modfied before thread creation concurrently?

// pseudocode for illustration
int g = 0;

void fn() {
  if (g == 1) {
    std::cout << "hello" << std::endl;
  } else {
    std::cout << "world" << std::endl;
  }
}

int main() {
  g = 1; // modified in main thread
  for (int i = 0; i < 5; ++i) {
    create_thread(fn);  // create threads
  }
  join(...)
  return 0;
}

I want to know does the C++ standard guarantee the code above will only output "hello"? Whether it's possible that store for g will be delayed after threads creation and other threads may read 0?

Upvotes: 2

Views: 124

Answers (1)

Nate Eldredge
Nate Eldredge

Reputation: 57922

Assuming that create_thread constructs a std::thread object calling fn(), then yes, it is safe. The program is free of data races and other UB, and must output hello.

A call to the std::thread constructor synchronizes with the start of the function that runs in the thread, see [thread.thread.constr p7] in C++20 N4860. The assignment to g is sequenced before the call to the constructor, and the start of fn() is sequenced before the evaluation of g, so it follows from the memory ordering rules that the assignment happens before the evaluation [intro.races p10]. This means in particular that these two operations do not cause a data race [intro.races p21]. Moreover, by write-read coherence [intro.races p18], the evaluation shall take its value either from the side effect g = 1, or from some other side effect in the evaluation order of g that follows the g=1 and is not excluded by some other rule.

In this program, the only side effects on g are its initialization to 0 and its assignment to 1, which clearly occur in that order in the modification order, so the evaluation cannot take the value 0 and must take the value 1.

If create_thread starts a thread in some other manner than via std::thread's constructor, which would necessarily be implementation-specific, then you would have to refer to the documentation for that mechanism. However, it is almost certain that any implementation-specific mechanism would follow these same semantics, since it would otherwise be very inconvenient to use.

Upvotes: 2

Related Questions