"Henk de Koning" wrote:

>     if (bNeedInit) {
>         lock(this) {
>             if (bNeedInit) {
>                 <init stuff>
>                 bNeedInit = false;
>             }

This is the classic double check lock for lazy initialization strategy.
Unfortunately, according to the strict definition of the .NET memory model,
this doesn't necessarily work - you can run into trouble due to the way that
the CLR allows multiprocessor caching architectures to reorder memory
accesses.

(It's broken under Java too for more or less exactly the same reasons by the
way.)

See Vance Morrison's excellent essay on this subject here:

 http://discuss.develop.com/archives/wa.exe?A2=ind0203B&L=DOTNET&P=R375

and the correction he posted after he realised it had a typo here:

http://discuss.develop.com/archives/wa.exe?A2=ind0203B&L=DOTNET&P=R25512


In brief, you will actually get away with the above code on the current CLRs
because Pentiums are relatively conservative about how they order their
memory accesses.  But there is the potential for it to be broken.  (Who
knows how it will behave on a multi-processor IA64 system, for example?)  To
fix it, you need to use a memory barrier operation.  Unfortunately the
memory barrier operations aren't directly available in the current release
of .NET - this article implies they will be in some future version.
(However, I believe you can get the same effect as the
System.Threading.Thread.MemoryBarrier(); by reading from and writing to a
volatile variable.)


--
Ian Griffiths
DevelopMentor

You can read messages from the DOTNET archive, unsubscribe from DOTNET, or
subscribe to other DevelopMentor lists at http://discuss.develop.com.

Reply via email to