Exclude reading and concurrency

Given the following simple code:

class Program { static bool finish = false; static void Main(string[] args) { new Thread(ThreadProc).Start(); int x = 0; while (!finish) { x++; } } static void ThreadProc() { Thread.Sleep(1000); finish = true; } } 

and running it in release mode using MSVS2015 (.NET 4.6), we get an endless application. This is because the JIT compiler generates code that reads finish only once, so it ignores any future updates.

Question: why does the JIT compiler allow this optimization? What part of the specification allows this?

+5
source share
2 answers

This is described in section 10.5.3 - "Flying Fields" in the C # Specification :

(I emphasized the part that covers your observations below)

10.5.3 Flying fields
When a field declaration includes a mutable modifier, the fields entered by this declaration are mutable fields.
For non-volatile fields, optimization methods that change the order of instructions can lead to unexpected and unpredictable results in multithreaded programs that access fields without synchronization , for example, provided by the lock operator (Β§8.12). These optimizations can be performed by a compiler, a runtime system, or hardware. For volatile fields, such reordering optimizations are limited:
* Reading a volatile field is called volatile reading. Intermittent reading has "acquire semantics"; that is, it is guaranteed to occur before any memory references that occur after it in a sequence of commands.
* Writing a volatile field is called volatile write. A volatile entry has "release semantics"; that is, it is guaranteed to happen after any memory references before a write command in a sequence of commands.
These restrictions ensure that all threads will observe mutable records executed by any other thread in the order in which they were executed. An appropriate implementation is not required to provide a single general order of volatile recording, as can be seen from all execution threads.

+8
source

The compiler thinks (does the following promises) as follows:

I will execute your code in the order in which you asked me, these are any instructions that are executed in your single-threaded code will be executed in the order in which they were written and based on this I will do any optimizations that please correspond single threaded sequence.

Well, the compiler sees the finish variable, which is not marked as volatile , and therefore he believes that it will not be changed by other threads, so he optimizes this, considering the condition always true. In debug mode, it has weaker thinking and does not perform this optimization.

Read more about it here .

+2
source

All Articles