[Mono-devel-list] Thread safety of readonly data members?

Jonathan Pryor jonpryor at vt.edu
Wed Feb 18 17:46:52 EST 2004


Below...

On Wed, 2004-02-18 at 11:06, gabor wrote:
> On Wed, 2004-02-18 at 12:49, Jonathan Pryor wrote:
> > Moving on to Mono, one major problem is that the CLI standard, as
> > currently specified, uses effectively the same memory consistency model
> > as Java.  Meaning, C++ techniques such as double-checked locking ARE NOT
> > VALID:

<snip what="double checked locking example"/>

> > In C++, you could use code similar to the above, and you WOULD NOT need
> > to lock both the class constructor and the accessor methods, as the
> > calling code ensures that the class has properly constructed before
> > invoking any member functions.

I forgot to mention this, but in C++ the static member would also need
to be declared as "volatile" for double-checked locking to properly
work, IIRC.
 
> > The problem is that double-checked locking isn't really portable in
> > .NET, so you either need to (a) always lock the code that will construct
> > the object, or (b) use the static loader lock, described below.
> 
> hmmm.. could you explain one more time why is that code wrong?
>  for example can you give me an example when it goes wrong?
> 
> for me it seems that it really guarantees that only 1 thread will be
> able to construct the object.

The problem is that the code (double-checked locking) *does* work.  On
x86.  And probably numerous other platforms.  But it's not *guaranteed*
to work on *all* platforms.  That's the problem.

See: http://blogs.msdn.com/cbrumme/archive/2003/05/17/51445.aspx

To quote (liberally) from Chris Brumme's blog:

	if (a == null)
	{
		lock(obj)
		{
			if (a == null) a = new  A();
		}
	}

	....

        However,  we have to assume that a series of stores have taken
        place during construction  of ‘a’.  Those stores can be 
        arbitrarily reordered, including the possibility of delaying
        them until after  the publishing store which assigns the new
        object to ‘a’.  At that point, there is a small window before
        the store.release implied by leaving the lock.  Inside that
        window, other CPUs can navigate through the reference ‘a’ and
        see a partially constructed  instance.
        
In other words, "Oops," because the memory model is (1) weaker than
developers expect, and (2) not reproducible on commodity hardware.

> and btw.  is reading or writing a native/simple/non-object ( i don't
> know the exact term for this. i mean something like int, char and so on)
> an atomic operation?

It's atomic if the object's size is less than a machine word.  So Int32
can be assumed to be read atomically on all platforms, but Int64 can not
(it'll be atomic on 64-bit platforms, but not in 32-bit x86).

Though, strictly speaking, this is machine/hardware/architecture
dependent.  You probably wouldn't want to assume this, but it's a fairly
reasonable assumption for most platforms.

> for example if i have two threads, one writes to a variable randomly 1
> or 10. the other thread reads the variable in a loop and writes it to
> the screen. can i be sure that i will only see the numbers 1 and 10? 

For all platforms I know of, yes.  But I don't know of all possible
platforms, and there's a potentially infinite number of future
platforms, so this isn't guaranteed to be true.  It will *probably* be
true, because if it weren't, a whole number of potential software
optimizations becomes difficult, but it's not a sure thing.

 - Jon





More information about the Mono-devel-list mailing list