Question

I have two pthreads which are reading/writing to a shared memory location. In one thread I keep checking for update to memory location. (Linux, Glibc)

Thread 1:

while(1) {
    if (ptr)
        ptr->do_something();
}

Thread 2:

ptr = update();

The point here is that I do not see the update being reflected even after a while. If I use synchronization barrier as follows, the update is immediately visible:

    while(1) {

    __sync_synchronize();
    if (ptr)
        ptr->do_something();
    }

So my questions are:

  1. Why is the update not visible even after a long time?
  2. What does __sync_synchronize() do exactly?

Edit 1: I understand why the update might not be visible immediately. My question is specifically why it is not visible even after a very long time.

Was it helpful?

Solution

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.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top