Q:

Parallel writes of a same value

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?

A:

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 with std::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.

A:

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.

