Reputation: 33391
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();
}
Upvotes: 5
Views: 275
Reputation: 28761
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.
Upvotes: 3
Reputation: 171246
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
.
Upvotes: 3
Reputation: 2733
Both samples complete in my case, but you're lambda/delegate can be compile differently in different compilers, which could be the problem.
You delegate are accessing a modified closure, which can cause a bunch of problems and you have apparently found one. Take a look at the answer provided by Jon Skeet here, Access to Modified Closure, it is not exactly the same problem, but the reason described here works in you case too.
Upvotes: 0