I think most people are aware of the following issue which happens when building in Release mode (code taken from Threading in C#):
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
}
due to compiler optimizations caching the value of complete
and thus preventing the child thread from ever seeing the updated value.
However, changing the above code a bit:
class Wrapper
{
public bool Complete { get; set; }
}
class Test
{
Wrapper wrapper = new Wrapper();
static void Main()
{
var test = new Test();
var t = new Thread(() =>
{
bool toggle = false;
while (!test.wrapper.Complete) toggle = !toggle;
});
t.Start();
Thread.Sleep(1000);
test.wrapper.Complete = true;
t.Join(); // Blocks indefinitely
}
}
makes the problem go away (i.e. the child thread is able to exit after 1 second) without the use of volatile
, memory fences, or any other mechanism that introduces an implicit fence.
How does the added encapsulation of the completion flag influence its visibility between threads?
But unfortunately, just like pain can make you feel worse mentally, your mind can cause pain without a physical source, or make preexisting pain increase or linger. This phenomenon is called psychogenic pain, and it occurs when your pain is related to underlying psychological, emotional, or behavioral factors.
Allodynia is defined as "pain due to a stimulus that does not normally provoke pain." An example would be a light feather touch (that should only produce sensation), causing pain.
But the truth is, pain is constructed entirely in the brain. This doesn't mean your pain is any less real – it's just that your brain literally creates what your body feels, and in cases of chronic pain, your brain helps perpetuate it.
We need the sensation of pain to let us know when our bodies need extra care. It's an important signal. When we sense pain, we pay attention to our bodies and can take steps to fix what hurts. Pain also may prevent us from injuring a body part even more.
I think you have answer in your question:
due to compiler optimizations caching the value of complete and thus preventing the child thread from ever seeing the updated value.
Compiler/JIT optimizations are performed whenever it makes sense/deemed safe and reasonable to implement. So you found case when optimization is not performed the way you expect to happen - maybe there is a good reason (someone detected this usage pattern and block optimization) or it just happen not to be optimized (most likely).
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With