Question

I am writing a program in C. FOR SIMPLICITY LETS SAY: There are several variables that many threads can both read and write. Every time one of these is written it is written via an atomic swap (GCC atomic operations, sync and swap). Do I need to use an atomic load every time I read one of these variables, or are the atomic writes sufficient to avoid reading in data mid-write?

Note, anywhere that needs to use data from one of these vars first copies the value:

int success = 0;
while ( !success ) {
  int x = shared_x;
  ... work with x, result in y ...
  success = cmp_swap( &shared_x, x, y );
}

My question is not about a data race, that is I am not concerned I might loose data. MY concern is that the value of shared_x might change halfway through my reading it. Say it is an 8-byte integer, would this be a potential problem: say shared_x is a 64-bit integer, 8 bytes. Would it be possible that my x = shared_x will copy the first 4 bytes, then something atomically writes to shared_x, then this statement finishes reading the second 4 bytes. This would result in x containing the first 4 bytes of an old value of shared_x, and the last 4 bytes of the new shared_x. I suspect the memory barrier in the atomic swap (http://gcc.gnu.org/onlinedocs/gcc-4.1.1/gcc/Atomic-Builtins.html - using __sync_bool_compare_and_swap) is enough to protect against this... but I am not sure.

Was it helpful?

Solution

It looks like you're reading from shared_x, calculate something new and then write back to shared_x. The value you write to shared_x seems to depend on the value you originally read from it.

If that is the case, you have a dependency there, and most probably need to not only make the read atomic, but you need to make the whole operation of "read, calculate, write back" atomic. Meaning, you need to synchronize it. Like with a mutex.

I say "most probably" because I can't be sure if I don't know what the code actually does. You need to analyze what happens in the case of a race condition where thread A writes to shared_x while thread B is currently doing a calculation based on the old value of shared_x and then writes the result back to it. The value written to it by thread A gets lost forever. I can't know whether this would be problematic for you. Only you can know that. If that race condition is OK, then you don't need to synchronize or make the read atomic.

If you're only interested in making sure that reading from shared_x will not get you garbage and don't care about the race condition described above, then the answer is "most probably you don't need to make the read atomic." Instead of me copy&pasting, you can read the details right here:

Atomicity in C++ : Myth or Reality

Even though the question is for C++, the same holds true for C as well.

Note though that atomics are now in the C standard as well (C11), provided by the <stdatomic.h> header and the _Atomic type qualifier. But of course not all compilers support C11 yet.

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