At my recent Async talk at DevWeek I built an Asynchronous queue that enables the consumers to take advantage of async and await keywords available in C# 5. You can download the code here, the final step in that implementation was to make use of double check locking. A delegate came up to me afterwards and said my code wasn’t thread safe, in that I could end up with a partially completed object. This was due to the fact that the CPU can re-order write operations to optimise memory bus, and that is true of some processors. In that the reference to the object could be flushed out to main memory before the data associated with the object constructor. This certainly was the case in .NET 1.1 with certain chip sets not true for your classic x86 and x64 but the Itanium I-A64 family of processor. The work around was to make the pointer to the constructed object volatile forcing the compiler to place the appropriate memory barrier instructions.
However in .NET 2.0 the CLR team enforced a more strong memory model since they didn’t like the idea of managed code behaving so differently on the final target hardware. Here is a link to the write up from MSDN mag by Vance Morrison the compiler architect of the .NET runtime explaining why you don’t need to use volatile from .NET 2.0 onwards.