Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can multiple threads write the same value to the same variable at the same time safely?

Can multiple threads write the same value to the same variable at the same time safely?

For a specific example — is the below code guaranteed by the C++ standard to compile, run without undefined behavior and print "true", on every conforming system?

#include <cstdio>
#include <thread>

int main()
{
    bool x = false;
    std::thread one{[&]{ x = true; }};
    std::thread two{[&]{ x = true; }};
    one.join();
    two.join();
    std::printf(x ? "true" : "false");
}

This is a theoretical question; I want to know whether it definitely always works rather than whether it works in practice (or whether writing code like this is a good idea :)). I'd appreciate if someone could point to the relevant part of the standard. In my experience it always works in practice, but not knowing whether or not it's guaranteed to work I always use std::atomic instead - I'd like to know whether that's strictly necessary for this specific case.

like image 298
Karu Avatar asked Jan 09 '20 01:01

Karu


People also ask

Can multiple threads read the same variable at the same time?

Assuming there are no more writes and all previous writes are visible to the current thread, then yes reading the value from multiple threads is safe.

Can multiple threads write to the same file?

There are several patterns on how to allow multiple threads to write to the same file. the ReaderWriterLock class is invented for this purpose. Another classic is using semaphors and the lock statement to lock a shared resource.

Can two threads use the same variable?

No. The definition of a data race is: multiple threads accessing the same location concurrently, at least one of them modifying it. If no thread writes to it, there is no data race. There may be a data race with the initialization of a variable, but that involves the initial write.

Can multiple threads write to the same array?

The answer is no. Each array element has a region of memory reserved for it alone within the region attributed the overall array. Modifications of different elements therefore do not write to any of the same memory locations.


1 Answers

No.

You need to synchronize access to those variables, either by using mutexes or by making them atomic.

There is no exemption for when the same value is being written. You don't know what steps are involved in writing that value (which is the underlying practical concern), and neither does the standard which is why code has undefined behaviour … which means your compiler can just make absolute mayhem with your program (and that's the real issue you need to avoid).

Someone's going to come along and tell you that such-and-such an architecture guarantees atomic writes to these sized variables. But that doesn't change the UB aspect.

The passages you're looking for are:

[intro.races/2]: Two expression evaluations conflict if one of them modifies a memory location ([intro.memory]) and the other one reads or modifies the same memory location.

[intro.races/21]: […] The execution of a program contains a data race if it contains two potentially concurrent conflicting actions, […]. Any such data race results in undefined behavior.

… and the surrounding wording. That section is actually quite esoteric, but you don't really need to parse it as this is a classic, textbook data race that you can read about in any book on programming.

like image 147
Lightness Races in Orbit Avatar answered Sep 20 '22 00:09

Lightness Races in Orbit