Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Variable caching

Why in this part of code complete is cached?

static void Main()
{
  bool complete = false; 
  var t = new Thread (() =>
  {
    bool toggle = false;
    while (!complete) toggle = !toggle;
  });
  t.Start();
  Thread.Sleep (1000);
  complete = true;
  t.Join();        // Blocks indefinitely
}

but in this part it isn't?

static void Main()
{
  bool complete = false;
  bool toggle = false; 
  var t = new Thread (() =>
  {
    while (!complete) toggle = !toggle;
  });
  t.Start();
  Thread.Sleep (1000);
  complete = true;
  t.Join();  
}
like image 488
Hamlet Hakobyan Avatar asked Feb 28 '13 22:02

Hamlet Hakobyan


2 Answers

You are doing unsynchronized data sharing across threads. Sirens should now go off.

As I understand the memory model the JIT is allowed to read complete once and store it in a register. For that reason the update from Main never becomes visible.

As for fixing this, the simplest way is to wrap a lock around accesses to complete. You could also use Thread.VolatileRead and Thread.VolatileWrite.

like image 108
usr Avatar answered Nov 20 '22 06:11

usr


Don't be sure caching will happen on all architectures as above, or even that it will always happen as above in multiple runs of the program.

It could be because in the second case the lambda is modifying the closure, while in first it is only accessing the closure. Of course this is only a wild guess.

More importantly though, there are no guarantees about when caching will be done, memory boundary only specifies when the thread will not use cached value.

Bottom line, you cannot rely on caching to occur.

like image 43
Miserable Variable Avatar answered Nov 20 '22 06:11

Miserable Variable