Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

Static Constructor and Deadlock

0.00/5 (No votes)
1 Oct 2013 1  
There is a potential opportunity of a deadlock if we perform any asynchronous blocking operation in a static constructor.

Static constructor is used to initialize the static members of a class. As per specification, static constructor is executed at most once in the given application domain and gets triggered by:

  • an instance of the class is created
  • any of the static members of the class are referenced

The CLR uses an internal lock to ensure that static constructor:

  • is only called once
  • gets executed before creation of any instance of the class or before accessing any static members.

With this behaviour of CLR, there is a potential opportunity of a deadlock if we perform any asynchronous blocking operation in a static constructor. Here is an example:

class Experiment
{
    public static readonly Experiment Instance;

    static Experiment()
    {
        Instance = new Experiment();
        Console.WriteLine("Initializing the instance on different thread");

        Thread thread = new Thread(() => Instance.Initialize());
        thread.Start();
        thread.Join();
        Console.WriteLine("Initialization completed");
    }

    void Initialize()
    {
        //Initializing members  
    }

    public void SayHello()
    {
        Console.WriteLine("Hello World");
    }
}

The main thread will wait for the helper thread to complete within the static constructor. Since the helper thread is accessing the instance method, it will first try to acquire the internal lock. As internal lock is already acquired by the main thread, we will end-up in a deadlock situation.

Even if the helper thread is not accessing any instance method, there is a risk that helper thread causes CLR to acquire the internal lock. Here is an example:

class Experiment
{
    static Experiment()
    {
        Thread thread = new Thread(()=>{});
        thread.Start();
        thread.Join();
    }
}

Another example with pLinq:

class Experiment
{
    public static readonly IEnumerable<int> SquaresOfFirst100Numbers;

    static Experiment()
    {
        Enumerable.Range(1, 100).AsParallel().Select(n => n * n).ToList();
    }
}

With this CLR behaviour, we should always avoid having any asynchronous blocking operation in static constructor as it can easily lead to a deadlock situation.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here