You're falling foul of an area that's not been standardised in C/C++ until very recently—the memory model.
The bottom line is that in the absence of synchronisation (in the broad sense of the term) there are no guarantees about when, or even if, changes made by one thread will be seen by another thread.
There's more to it than just when (or if) something will become visible—it also affects ordering. So this kind of thing, for example, is completely unsafe:
bool important_data_ready = false;
// In thread 1
void* important_data = calculate_important_data();
important_data_ready = true;
// In thread 2
if (important_data_ready) {
// use important_data
}
Because it would be quite possible for important_data_ready
to become true
from the point of view of thread 2 before thread 1's write to important_data
is visible from that thread's point of view. Worse, in the absence of standardisation on how this should work, the details have varied between compilers and CPUs.
This stuff has been standardised in Java since Java 5 (2004) but only became standardised in C/C++ in C11 and C++11.
The __sync_synchronize
function you're using is a legacy gcc facility that issues a full memory barrier—in a nutshell, this ensures that everything done by the thread before that memory barrier will be visible to another thread before anything done after the memory barrier. But you're not using it safely—it also needs to be used by the reading thread for full safety.
You're probably better off, if you can, using the new standardised mechanisms supported by C11. This talk by Herb Sutter is a good starting point.