1

I'm using InterlockedExchange in Windows and I have two questions that put together are basically my title question.

InterlockedExchange uses type LONG (32-bits). According to Microsoft's documentation Interlocked Variable Access: "simple reads and writes to 32-bit variables are atomic operations without InterlockedExchange". According to function documentation InterlockedExchange: "This function is atomic with respect to calls to other interlocked functions". Is it or is it not atomic to read/write a LONG in Windows without the interlocked functions?

I am reviewing some code in which one thread sets a variable then all further accesses on that variable by that thread or any number of threads it created use InterlockedExchange. To make it simple consider thread running main() creates a thread running other():

LONG foo;

main()
{
  foo = TRUE;
  createthread(other());
  /* do other things */
  if(InterlockedExchange(&foo, 0))
  {
     cleanup()
  }
}

other()
{
  /* do other things */
  if(InterlockedExchange(&foo, 0))
  {
     cleanup()
  }
}

cleanup()
{
/* it's expected this is only called once */
}

Is it possible in this example that foo will not appear TRUE to either of the InterlockedExchange calls? If main is busy doing other things so that the first InterlockedExchange call is made from the other thread, does that mean foo is guaranteed to have been written by the main thread and visible to the other thread at that time?

Sorry if this is unclear I don't know how to phrase it better.

newguy
  • 617
  • 6
  • 15
  • See [In C/C++, are volatile variables guaranteed to have eventually consistent semantics betwen threads?](https://stackoverflow.com/questions/3114124/in-c-c-are-volatile-variables-guaranteed-to-have-eventually-consistent-semant) for more pointers and discussion of a somewhat related question. – dxiv Nov 21 '20 at 03:58

1 Answers1

1

Is it or is it not atomic to read/write a LONG in Windows without the interlocked functions?

Yes to both, assuming default alignment. This follows from the quoted statement "simple reads and writes to properly-aligned 32-bit variables are atomic operations", because LONG is a 32-bit signed integer in Windows, regardless of the bitness of the OS.

Is it possible in this example that foo will not appear TRUE to either of the InterlockedExchange calls?

No, not possible if both calls are reached. That's because within a single thread the foo = TRUE; write is guaranteed to be visible to the InterlockedExchange call that comes after it. So the InterlockedExchange call in main will see either the TRUE value previously set in main, or the FALSE value reset in the other thread. Therefore, one of the InterlockedExchange calls must read the foo value as TRUE.

However, if the /* do other things */ code in main is an infinite loop while(1); then that would leave only one InterlockedExchange outstanding in other, and it may be possible for that call to see foo as FALSE, for the same reason as...

If main is busy doing other things so that the first InterlockedExchange call is made from the other thread, does that mean foo is guaranteed to have been written by the main thread and visible to the other thread at that time?

Not necessarily. The foo = TRUE; write is visible to the main thread at the point the secondary thread is created, but may not necessarily be visible to the other thread when it starts, or even when it gets to the InterlockedExchange call.

dxiv
  • 16,984
  • 2
  • 27
  • 49
  • Wouldn't creating the `other` thread cause some sort of cache flush or memory write so that everything up to that point is visible to the other threads? – newguy Nov 22 '20 at 21:54
  • @newguy Maybe so, but I did not find such a guarantee spelled out in the reference docs. – dxiv Nov 22 '20 at 22:05
  • 1
    Ok. I have marked your answer as correct. Thanks for your help! – newguy Nov 23 '20 at 03:34
  • @newguy Glad/hope it helped. About the last part specifically, the [Synchronization and Multiprocessor Issues](https://learn.microsoft.com/en-us/windows/win32/sync/synchronization-and-multiprocessor-issues) page lists functions related to critical sections, synchronization objects, wait and interlocked access as using "*the appropriate barriers to ensure memory ordering*" but `CreateThread` is not in that list. – dxiv Nov 23 '20 at 04:14