Is the popular “volatile polled flag” pattern broken?

瘦欲@ 提交于 2019-12-02 20:47:07

If I call Start() at 0s and Stop() at 3s on another thread, is the loop guaranteed to exit at the end of the current iteration at around 10s?

Yes, 7 seconds is definitely sufficient for one thread to percieve change of _stopping variable.

Almost-formal explanations

For every variable which provides any type of visibility barrier (memory order), specification for any language should provide a garantee that:

Any change of the variable (with special memory order) from one thread will be observed in other threads during finit and bounded period of time.

Without this garantee, even memory order features of the variable are useless.

Specification for C# definitely provides such garantee about volatile variable, but I cannot find corresponded text.

Note, that such garantee about finit time is unrelated to memory orders garantees ("acquire", "release" and so on), and it cannot be deduced from the definitions of barriers and memory orders.

Formal-informal explanations

When say

I call Stop() at 3s

one implies, that there was some visible effect (e.g., information printed into the terminal), which allows him to claim about 3s timestamp (because print statement has been issued after the Stop()).

With that C# spec plays gracefully ("10.10 Execution order"):

Execution shall proceed such that the side effects of each executing thread are preserved at critical execution points. A side effect is defined as a read or write of a volatile field, a write to a non-volatile variable, a write to an external resource, and the throwing of an exception. The critical execution points at which the order of these side effects shall be preserved are references to volatile fields (§17.4.3), lock statements (§15.12), and thread creation and termination.

Assuming printing is a critical execution point (likely it uses locks), you may be confident that at the moment assignment to _stopping volatile variable as a side effect is visible to the other thread, which checks given variable.

Informal explanations

While a compiler is allowed to move assignment of volatile variable forward in the code, it cannot do that indefinitely:

  • the assignment cannot be moved after the function call, because the compiler cannot assume anything about the function's body.

  • If assignment is performed inside a cycle, it should be completed before another assigment in the next cycle.

  • while one can imagine code with 1000 consecutive simple assignments (to other variables), so volatile assignment could be deffered for 1000 instructions, the compiler simply does perform such deffering. And even if it does, execution of 1000 simple instructions on modern CPU takes no more than several microseconds.

From the side of a CPU, situation is simpler: none CPU will deffer assignment to memory cell more than limited number of instructions.

In total, assignment to volatile variable can be deffered only on very limited number of instructions.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!