The Artima Developer Community
Sponsored Link

.NET Buzz Forum
thread safety and static variable instantiation

0 replies on 1 page.

Welcome Guest
  Sign In

Go back to the topic listing  Back to Topic List Click to reply to this topic  Reply to this Topic Click to search messages in this forum  Search Forum Click for a threaded view of the topic  Threaded View   
Previous Topic   Next Topic
Flat View: This topic has 0 replies on 1 page
Steve Hebert

Posts: 218
Nickname: sdhebert
Registered: Apr, 2005

Steve Hebert is a .NET developer who has created the .Math compiler library.
thread safety and static variable instantiation Posted: Dec 16, 2005 3:14 AM
Reply to this message Reply

This post originated from an RSS feed registered with .NET Buzz by Steve Hebert.
Original Post: thread safety and static variable instantiation
Feed Title: Steve Hebert's Development Blog
Feed URL: /error.htm?aspxerrorpath=/blogs/steve.hebert/rss.aspx
Feed Description: .Steve's .Blog - Including .Net, SQL Server, .Math and everything in between
Latest .NET Buzz Posts
Latest .NET Buzz Posts by Steve Hebert
Latest Posts From Steve Hebert's Development Blog

Advertisement

A coworker asked me a question today about initialization of static member variables and how they relate to static constructors.   He also told me about an article he read that the following code isn't safe:

 

if( _myObj == null )

{

            Lock( _lockObj )

            {

                        If( _myObj ==  null )

                                    _myObj = new MyObject(…);

            }

}

 

He definitely had my attention ... He passed along an article on implementing a thread-safe singleton pattern in C# and the article is a very interesting read.  To be fair up front, the above code works in the microsoft implementation (according to Chriss Brumme and discussed later), but the ECMA spec is vague on how instantiation must take place.  On the other hand, the above code is explicitly NOT threadsafe in Java.  The article also discusses the way in which the .Net runtime chooses to instantiate static member variables and this section was news to me.

 
Double Locking and Thread Safety


The above code looks right until you read Chris Brumme's Memory Model blog entry.  The excerpt that finally makes sense after reading this a couple of times is:

 

... (W)e 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.

 

So what does this mean?   In the assignment of a new operator, this piece of code could be broken by a weak but valid implementation of the ECMA spec.   Given the following line of code:

 

_myObj = new MyObject();

 

We expect that the underlying pseudo code looks something like this:

\n

 

\n

Allocate MyObject memory and assign it to tempObj

\n

Call Constructor on tempObj

\n

assign tempObj to _myObj

\n

 

\n

Given the state of the ECMA spec, a valid implementation could be this:

\n

 

\n

Allocate MyObject memory and assign it to _myObj

\n

Call Constructor on _myObj

\n

 

\n

In this second implementation, consider what happens if the thread holding the lock gets preempted between Allocate and the Constructor call.\n  A thread that doesn\'t hold the lock believes the construction of _myObj is complete and proceeds with a partially initialized variable. Doh!

\n

 

\n

If I want to do double check locking in a truly safe manner that complies with the ECMA spec, I have to write:

\n

 

\n

 

\n

if( _myObj \u003d\u003d null )

\n

{

\n

",1] ); //-->We expect that the underlying pseudo code looks something like this:

 

Allocate MyObject memory and assign address to tempObj

Call Constructor on tempObj

assign tempObj to _myObj

 

Given the state of the ECMA spec, a valid implementation could be this:

 

Allocate MyObject memory and assign it to _myObj

Call Constructor on _myObj

 

In this second implementation, consider what happens if the thread holding the lock gets preempted during the Constructor call.   A thread that doesn't hold the lock believes the construction of _myObj is complete and proceeds with a partially initialized variable.

 

If I want to do double check locking in a truly safe manner that complies with the ECMA spec, I have to write:

 

 

if( _myObj == null )

{

            Lock(_lockObj)

\n

            {

\n

                        if( _myObj \u003d\u003d null )

\n

                        {

\n

                                    MyObject tempObj \u003d new MyObject(…);

\n

                                    _myObj \u003d tempObj;

\n

                        }

\n

            }

\n

}

\n

 

\n

Interesting.

\n

 

\n

As I mentioned earlier, the Microsoft version of the CLR enables the first version to run correctly.  Because of the spec, it\'s a valid point of concern with non-Microsoft implementations of the CLR.\n   If you want to compare this behavior to Java, the Java memory model explicity doesn\'t support double-locking – even though it\'s commonly done.\n

\n

 

\n

 

\n",0] ); //-->            Lock(_lockObj)

            {

                        if( _myObj == null )

                        {

                                    MyObject tempObj = new MyObject(…);

                                    _myObj = tempObj;

                        }

            }

}

 

As I mentioned earlier, the Microsoft version of the CLR enables the first version to run correctly (post .Net 1.0).  Because of the spec, it's a valid point of concern with non-Microsoft implementations of the CLR that can be easily answered.   Given that double-lock checking in Java is not supported, it has me wondering...  is this a holdover from Java's days as a stack-based compiler?  Can a stack-based compiler create an object structure without first allocating the memory to the host pointer and then calling the constructor?


Static Variable Instantiation


Another interesting part of the article discusses static member instantiation and how the mechanics work.  Given a class where two static members exist:

public class Ugly
{
    public static Ug _Ug = new  Ug();
    public static Lee _Lee = new Lee();
}

The static variables are not created until I access one of the members which I would expect.  When I access one of the members before instantiating the class, both static objects are actually instantiated before returning the result. This was a surprise to me.   It turns out the C# compiler marks the class with beforefieldinit.   (The behaviors surrounding beforefieldinit are interesting and certainly worth reading.)  The way to get around this behavior is to define the class as follows:

public UglyClass
{
    public static Ug = new  Ug();
    public static Lee - new Lee();

    static UglyClass() {}
}

When C# sees a static constructor, the type is not marked with the beforefieldinit attribute.  Therefore each static object is instantiated upon first reference.


Read: thread safety and static variable instantiation

Topic: Windows Live Messenger revealed Previous Topic   Next Topic Topic: Wouldn't you like to respond to your user's issues and bug reports like this?

Sponsored Links



Google
  Web Artima.com   

Copyright © 1996-2019 Artima, Inc. All Rights Reserved. - Privacy Policy - Terms of Use