2

Given the following class:

class C
{
   public int x = 0;

   public void F() {
       new Thread(G).Start();
       while (x == 0) { Thread.Sleep(TimeSpan.FromMilliseconds(1)); }
   }

   public void G() {
      Thread.Sleep(TimeSpan.FromMilliseconds(1000));
      Interlocked.Exchange(ref x, 1);
   }
}

I assume it is allowed under the C# standard for new C().F() to run forever yes, because there's nothing to force F() to retrieve the value of x from main memory each access. The Interlocked.Exchange here even doesn't help, as F() doesn't see the implementation of G() so may optimise away the access from main memory.

Is this analysis correct?

Furthermore, I understand making x volatile will resolve this, but is there anything else that would resolve this issue?

Clinton
  • 22,361
  • 15
  • 67
  • 163
  • Don't use `volatile` in C#, unless you really, *really* know your way around it: https://stackoverflow.com/a/19384758/1086121. A normal `lock` statement is the way to go about this. – canton7 Mar 18 '19 at 10:40
  • As canton7 mentioned, locking the object will force other threads to wait (thus syncrhonize) for the locking thread to release it thus making it atomic. – Kieran Devlin Mar 18 '19 at 10:44
  • 1
    Writes *are* seen by other threads. Assuming there *are* other threads to see the writes - `new Thread(G).Start();` creates an orphaned thread object that's going to get garbage-collected – Panagiotis Kanavos Mar 18 '19 at 10:47
  • 1
    Even if that's solved, *reading* needs synchronization as well, either through a lock or `Interlocked.CompareExchange` – Panagiotis Kanavos Mar 18 '19 at 10:48
  • If `int` is not larger than native word size, then read/write is atomic : https://stackoverflow.com/a/9788/397807 – tia Mar 18 '19 at 11:32
  • C# spec also guarantees atomicity : https://stackoverflow.com/questions/9666/is-accessing-a-variable-in-c-sharp-an-atomic-operation#comment21288539_9788 – tia Mar 18 '19 at 11:34
  • 1
    You can use also `Thread.VolatileWrite` and `Thread.VolatileRead` (as a replacement of `volatile` keyword). `Interlocked.Exchange` isn't needed here at all as int32 assignment is atomic. – Dmytro Mukalov Mar 18 '19 at 11:34
  • I think the fact that in his example the object assignment is on an `Int32` is just a coincidence (from the perspective of the OP). I think the question is more geared towards if the reference assignment isn't an object that is atomic. – Kieran Devlin Mar 18 '19 at 13:06
  • I understand the writes are atomic for anything except custom structs, the issue is seeing the changes, not whether they’re atomic. – Clinton Mar 18 '19 at 13:08
  • I think @DmytroMukalov 's `VolatileRead` and `VolatileWrite` is all that is required here. Thanks! – Clinton Mar 18 '19 at 13:10

1 Answers1

0

Use the lock statement to force other threads to wait for it to become unlocked.

https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/lock-statement

Kieran Devlin
  • 1,373
  • 1
  • 12
  • 28