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

Reply via email to