With regard to compiler optimizations (C#-to-IL or IL-to-native, AKA JIT) I don't think 335 is clear.
It's very clear with respect to CPU caching. Monitor.Enter is an implicit memory barrier, all CPU cached writes will be flushed to RAM (meant specifically for the object being locked; but most processors don't have that level of granularity so the whole cache is flushed). Monitor.Exit does the same, it flushes any CPU-cached writes that may have occurred since Monitor.Enter. Essentially, that's the "acquire semantics" and "release semantics": ensuring processor/core-specific cached-writes are flushed to RAM for all processors to see. Almost consistently is "acquire semantics" and "release semantics" associated only with CPU write caching and never with compiler optimizations. The distinction between acquire/release semantics and compiler optimizations is evident in both the previously mentioned links: http://msdn2.microsoft.com/en-us/library/ms954629.aspx http://msdn2.microsoft.com/en-us/library/ms998558.aspx Similar details can be seen throughout MSDN with regard to "acquire semantics" and "release semantics" http://msdn2.microsoft.com/EN-US/library/aa490209.aspx Discusses the acquire semantics of specific Win32 functions, nothing to do with compiler optimizations and no existing native compiler I know of changes it's optimization behaviour in the presence of those Interlocked functions. http://msdn2.microsoft.com/en-us/library/ms686355.aspx Details that prior to VC 2003 "volatile" had no acquire/release semantics and only dealt with compiler optimizations. Historically "volatile" in C/C++ is only ever been a signal to the compiler not to optimize a variable, it had nothing to do with CPU-write- caching. I don't know exactly when "volatile" appeared in C/C++; but it had to have been as soon (or very shortly after) the first optimizing compiler (30+ years?) Most of the the Interlock* methods in Win32 are documented as providing full memory barriers, but only those that end in Acquire or Release have "acquire semantics" or "release semantics". These Acquire/Release functions, of course, have no bearing on what the compiler does with variables not declared with "volatile". The only place where 335 is specific about compiler optimizations is in 12.6.7 where mentions the "compiler...shall not remove any volatile operation". Keep in mind, nothing between Monitor.Enter and Monitor.Exit is a volatile operation. 12.6.7 has some informative text involving registers, volatile operations, and optimizing compilers reordering code, but it's not normative; but it only mentions reordering read/writes of members if they are volatile reads/writes or single thread semantics (also only applies to volatile operations). 12.6.4 defines "visible side- effects" as those resulting from volatile operations; 12.6.7 details volatile operations as having either acquire or release semantics, and 12.6.4 details ordering guarantees with respect to "visible side-effects". -- Peter On Mon, 9 Jul 2007 04:24:21 -0400, Greg Young <[EMAIL PROTECTED]> wrote: >"Note that the MSDN patterns and practices article linked previously >[1] suggests to use the volatile keyword. It's from 2002, however, so >it's based on one of the 1.1 memory models. There is a second article >(without date, but it is more recent), which also suggests using >volatile [2]. I have also read some blog entries by Joe Duffy (e.g. >[3]) where he states he believes that some _variants_ of the >double-checked locking patterns are broken (e.g. if you use a boolean >flag to indicate whether the variable was initialized or not)." > >I guess 15.5.6 isnt clear.. > >"Acquiring a lock (System.Threading.Monitor.Enter or entering a >synchronized method) shall implicitly >perform a volatile read operation, and releasing a lock >(System.Threading.Monitor.Exit or leaving a >synchronized method) shall implicitly perform a volatile write >operation. See §12.6.7." > > >This brings us to the interesting point, why is there disagreement? >This is a very clear statement that monitor is indeed a superset of >volatile. > >In the x86 JIT nearly EVERYTHING is considerred volatile, perhaps the >others dont follow the spec? > >Cheers, > >Greg > > >On 7/9/07, Fabian Schmied <[EMAIL PROTECTED]> wrote: >> > internal abstract class BaseManager<I> where I: IEntityProvider >> > { >> > private static I _provider = default(I); >> > private static object _syncLock = new object(); >> > >> > protected static I Provider >> > { >> > if (_provider == null) >> > { >> > lock (_syncLock) >> > { >> > if (provder = null) >> > provider = >> > Activator.createfromconfig(...); >> > } >> > } >> > return _provider; >> > } >> >> The double-check locking pattern is a low-lock solution to a >> multithreading problem, and it is therefore: >> >> a - tempting, because efficient, >> b - controversial, because complicated. >> >> It is controversial, because it is very hard to say whether it will be >> thread-safe on all processor architectures and all jitters with the >> .NET memory model. It requires detailed knowledge of the memory model >> (which is different between the .NET 1.1 ECMA specification, the .NET >> 1.1 x86 MS implementation, and the .NET 2.0 >> specification/implementations), and even then experts argue both ways. >> I believe this is why Jon Skeet discourages from using it. >> >> In particular, it is currently not exactly clear to me whether your >> implementation will be safe on all platforms or not, because your >> _provider member is not marked as volatile. >> >> Note that the MSDN patterns and practices article linked previously >> [1] suggests to use the volatile keyword. It's from 2002, however, so >> it's based on one of the 1.1 memory models. There is a second article >> (without date, but it is more recent), which also suggests using >> volatile [2]. I have also read some blog entries by Joe Duffy (e.g. >> [3]) where he states he believes that some _variants_ of the >> double-checked locking patterns are broken (e.g. if you use a boolean >> flag to indicate whether the variable was initialized or not). >> >> Also, solutions using double-checked locking are so incredibly hard to >> test, because if you get something wrong, it will usually not show on >> x86 with the current JIT compiler. It will only show on other >> architectures (e.g. IA64) or with other JIT compilers. And even on >> such platforms, it will only show occasionally, without being >> reproduceable. >> >> Bottom line: Lock-free (or low-lock) multithreading is so complicated >> that I believe you should typically use another alternative. The >> performance gain is minimal. If you have a situation where you >> absolutely need it, use volatile or get really, really involved with >> the topic to learn whether you can leave it out. >> >> Fabian >> >> [1] http://msdn2.microsoft.com/en-us/library/ms954629.aspx >> [2] http://msdn2.microsoft.com/en-us/library/ms998558.aspx >> [3] http://www.bluebytesoftware.com/blog/PermaLink,guid,543d89ad-8d57- 4a51-b7c9-a821e3992bf6.aspx =================================== This list is hosted by DevelopMentor® http://www.develop.com View archives and manage your subscription(s) at http://discuss.develop.com
