Can this C# code fail because of a value in a register or cache never getting written back to main memory?

c#, caching, multithreading

Solution

if the compiler doesn't perform that optimization, is there still potential for the loop to run forever on a multiprocessor machine due to one processor updating _flag in a register or cache and never flushing that cache back to memory readable by the other thread?

Yes.

I've read that "C# writes are volatile," but the article I linked to says this is not actually guaranteed by the ECMA spec and things aren't implemented that way on ARM.

How is that relevant? The main thread isn't writing, it's reading.

I'm trying to figure out how paranoid I have to be to write threaded code that will work on all platforms.

It's not paranoia if they really are out to get you. Threading is hard. Do what I do: leave low-level manipulation of shared memory to experts.

Write your code using the highest possible level of abstraction, with the abstractions written for you by experts. You should almost never write the code as you described, not because it's wrong -- though it is -- but because it's at the wrong level of abstraction. If you want to represent the idea of "this operation can be cancelled" then use a `CancellationToken`; that's what they're for. If you want to represent the notion of "this work produces its result in the future", use a `Task<T>`; that's what they're for. Don't try to roll your own; let Microsoft do it for you.

UPDATE: For more information about thread safety in C#, volatile semantics, low-lock techniques, and why you should avoid doing all of these things yourself, see:

Vance's awesome 2005 article on low lock techniques:

http://msdn.microsoft.com/en-us/magazine/cc163715.aspx

My 2011 series of three articles which begins here:

http://ericlippert.com/2011/05/26/atomicity-volatility-and-immutability-are-different-part-one/

In particular the third is relevant to you but the first two might be interesting as well.

Joe Duffy reiterates why you should not use volatile:

http://joeduffyblog.com/2010/12/04/sayonara-volatile/

My 2014 pair of Ask The Bug Guys articles:

http://blog.coverity.com/2014/03/12/can-skip-lock-reading-integer/ http://blog.coverity.com/2014/03/26/reordering-optimizations/

I've given those in a reasonable reading order; if you're finding Vance's article too difficult going, try starting with my three-part series instead and then go back to it.

Problem

In this article: http://msdn.microsoft.com/en-us/magazine/jj883956.aspx the author states that the following code can fail due to "loop read hoisting": ``` class Test { private bool _flag = true; public void Run() { // Set _flag to false on another thread new Thread(() => { _flag = false; }).Start(); // Poll the _flag field until it is set to false while (_flag) ; // The loop might never terminate! } } ``` In loop read hoisting, the compiler may change the while loop above to the following because of a single-thread assumption: ``` if (_flag) { while (true); } ``` What I'm wondering is this: if the compiler doesn't perform that optimization, is there still potential for the loop to run forever on a multiprocessor machine due to one processor updating _flag in a register or cache and never flushing that cache back to memory readable by the other thread? I've read that "C# writes are volatile," but the article I linked to says this is not actually guaranteed by the ECMA spec and things aren't implemented that way on ARM. I'm trying to figure out how paranoid I have to be to write threaded code that will work on all platforms. Here is a related question: Can a C# thread really cache a value and ignore changes to that value on other threads? but I think the code in the accepted answer is probably getting optimized with loop read hoisting, so it proves nothing about memory visibility...

Original source

Related problems