Are race conditions that write the same value safe?

Viewed 319

Suppose I have some multi-threaded program using shared memory, in which multiple threads are at random times overwriting the value of some multi-byte variable (e.g. an int or a double), sometimes colliding which each other (a.k.a. a race condition), and reading the value from the same variable at random times too.

Assuming all the threads always write the same value to the memory address (e.g. each thread does x = 1000) - if a thread reads the variable at the exact moment that another thread(s) is/are overwriting it, is the variable guaranteed to have the correct value? or could the memory somehow get overwritten with something random?

That is, if all the threads always write x = 1000, can a thread read x and get something other than 1000?

2 Answers

Assuming all the threads always write the same value to the memory address (e.g. each thread does x = 1000) - if a thread reads the variable at the exact moment that another thread(s) is/are overwriting it, is the variable guaranteed to have the correct value?

The C language specifications expressly decline to make such a guarantee by declaring the behavior of programs containing race conditions to be undefined. And you're right that without synchronization, the situation you describe is a race condition, notwithstanding whether the value being written is the same is the initial contents of the memory.

or could the memory somehow get overwritten with something random?

The behavior is undefined. In principle, anything could happen, including the read seeing a value that was never stored at the location in question.

Note also that the race is not about any kind of objective simultaneity. Rather, it is about lack of synchronization that would prevent simultaneous access, regardless of whether any simultaneous access actually occurs.

In practice, you would probably find that on some implementations, under at least some circumstances, writes that do not change the contents of memory act as if they did not conflict with each other or with reads that happen after that value was first written to the location, where "happens after" is a technical term that depends in part on synchronization. I do not recommend depending on such behavior, however. Not even if it is documented.

The C Standard allows implementations which can cheaply offer stronger guarantees than what it mandates to do so. Consequently, the Standard bends over backward to avoid requiring implementations to uphold any guarantees whose costs might sometimes exceed their benefits, leaving the question of how and when to uphold guarantees whose benefits would exceed the costs as a Quality of Implementation outside the Standard's jurisdiction.

Although it would seem like it should cost nothing to guarantee that writing an object with the value it already contains would have no effect, upholding such a guarantee would sometimes require foregoing some potentially-useful optimizations. As a simple example, consider the following function

volatile zz;
unsigned test(unsigned *p, unsigned *q)
{
  unsigned temp;
  *p = 0x1234;
  temp = *q;
  zz = 1;
  do {} while(zz);
  *p = 0x1235;
  return temp;
}

On some platforms, including the original 8088/8086, the most efficient way to process the code may be to replace the last assignment to *p with *p += 1; which could then be processed using an inc instruction. If the code were executed in two threads simultaneously, however, that could cause *p to be left holding the value 0x1236.

In many cases, upholding a guarantee that writing an object with the value it already contains would cost nothing, while treating race conditions involving such writes as benign would eliminate the cost of some synchronization actions that would be rendered unnecessary. Unfortunately, while the Standard allows implementations to offer guarantees beyond what the Standard requires when doing so would be practical and useful, it provides no means of distinguishing implementations that offer such guarantees from those that don't.

Related