This is a continuation of the discussion on multithreading issues in C#.
In C++, unprotected access to the shared data from multiple threads is an undefined behavior* if there is a write operation involved. What is it in C#? As (the safe part of) C# doesn't contain undefined behaviors, are there any guarantees? C# seems to have a kind of as-if rule as well, but after reading the mentioned part of the standard I fail to see what are the consequences of an unprotected data access from the language point of view.
In particular, it's interesting to know which kind of optimizations including load fusing and invention are prohibited through the language. This prohibition would imply the validity (or the lack thereof) of several popular patterns in C# (including the one discussed in the original question).
[The details of the actual implementation in Microsoft CLR, despite being very interesting, are not the part of this question: only the guarantees given by the language itself (and therefore portable) are here under discussion.]
The normative references are very welcome but I suspect the C# standard has enough information on the topic. Maybe someone from the language team can shed some light on what are the actual guarantees which are going to be included into the standard later but can be relied upon right now.
I suspect that there are some implied guarantees like the absence of pointer reference tearing because this could easily lead to breaking the type safety. But I'm not an expert on the topic.
*Often shortened as UB. Undefined Behavior allows a C++ compiler to produce literally any code, including formatting the hard disk or whatever, or to crash at compile time.