I have a program which spawns multiple threads that may write the exact same value to the exact same memory location:
std::vector<int> vec(32, 1); // Initialize vec with 32 times 1
std::vector<std::thread> threads;
for (int i = 0 ; i < 8 ; ++i) {
threads.emplace_back([&vec]() {
for (std::size_t j = 0 ; j < vec.size() ; ++j) {
vec[j] = 0;
}
});
}
for (auto& thrd: threads) {
thrd.join();
}
In this simplified code, all the threads may try to write the exact same value to the same memory location in vec
. Is this a data race likely to trigger undefined behavior, or is it safe since the values are never read before all the threads are joined again?
If there is a potentially hazardous data race, will using a std::vector<std::atomic<int>>
instead with std::memory_order_relaxed
stores instead be enough to prevent the data races?
Language-lawyer answer, [intro.multithread] n3485
21 The execution of a program contains a data race if it contains two conflicting actions in different threads, at least one of which is not atomic, and neither happens before the other. Any such data race results in undefined behavior.
4 Two expression evaluations conflict if one of them modifies a memory location and the other one accesses or modifies the same memory location.
will using a
std::vector<std::atomic<int>>
instead withstd::memory_order_relaxed
stores instead be enough to prevent the data races?
Yes. Those accesses are atomic, and there's a happens-before relationship introduced via the joining of the threads. Any subsequent read from the thread spawning those workers (which is synchronized via .join
) is safe and defined.
It is a data race and compilers will eventually become smart enough to miscompile the code if they are not already. See How to miscompile programs with "benign" data races section 2.4 for why writes of the same value break the code.
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