kmp
kmp

Reputation: 10865

Why no deadlock in this scenario?

So I was happily reading this from Eric Lippert and then, of course, the excellent comments and in them John Payson said:

a more interesting example might have been to use two static classes, since such a program could deadlock without any visible blocking statements.

and I thought, yeah, that'd be easy so I knocked up this:

public static class A
{     
    static A()
    {
        Console.WriteLine("A.ctor");
        B.Initialize();
        Console.WriteLine("A.ctor.end");
    }

    public static void Initialize()
    {
        Console.WriteLine("A.Initialize");
    }
}
public static class B
{
    static B()
    {
        Console.WriteLine("B.ctor");
        A.Initialize();
        Console.WriteLine("B.ctor.end");
    }

    public static void Initialize()
    {
        Console.WriteLine("B.Initialize");
    }

    public static void Go()
    {
        Console.WriteLine("Go");
    }
}

The output of which (after calling B.Go()) is:

B.ctor
A.ctor
B.Initialize
A.ctor.end
A.Initialize
B.ctor.end
Go

No deadlock and I am am obviously a loser - so to perpetuate the embarrassment, here is my question: why no deadlock here?

It seems to my tiny brain that B.Initialize is called before the static constructor of B has finished and I thought that that was not allowed.

Upvotes: 10

Views: 223

Answers (5)

D J
D J

Reputation: 7028

Why you think there should be a deadlock. Static constructors are called only once. No matter how many time you execute statement B.Initialize(); it will call the static constructor of class B only first time when B is referred. See more on static constructors here.

Upvotes: 1

Daniel Hilgarth
Daniel Hilgarth

Reputation: 174309

The important point is that there is only one thread involved. Quote from the blog post:

The static constructor then starts up a new thread. When that thread starts, the CLR sees that a static method is about to be called on a type whose static constructor is "in flight" another thread. It immediately blocks the new thread so that the Initialize method will not start until the main thread finishes running the class constructor.

In Erics example, there are two threads waiting for each other. You only have one thread, so there is no waiting happening and as a consequence: no blocking and no deadlock.

Upvotes: 1

pickypg
pickypg

Reputation: 22332

It's not a deadlock because you're not doing anything that should block, nor are you doing anything that should break.

You are not using any resources from A within B, and vice versa. As a result, your circular dependency is "safe" in the sense that nothing will explode.

If you trace the path that your printouts show, then nothing should block:

  1. Call Go (I suspect)
  2. Enter B (static constructor) as it is not initialized.
  3. Print out
  4. Use A.Initialize()
  5. A's static constructor is required to execute first
  6. Print out
  7. Use B.Initialize()
  8. B does not need to initialize, but it's not in a completed state (fortunately no variables are being set, so nothing breaks)
  9. Print out, then return
  10. Print out (from A's static constructor), then return
  11. A.Initialize() can finally be called because A is initialized
  12. Print out, then return
  13. Print out (from B's static constructor), then return
  14. Go

The only thing that you really did was present the potential for an unsafe state: accessing a class whose constructor had not finished executing. That is unsafe code, and while not blocking, definitely represents a broken state.

Upvotes: 6

Leff
Leff

Reputation: 582

The class instance is actually created before constructor call, thus there's no need to execute constructor anymore.

Upvotes: -3

Shiva Komuravelly
Shiva Komuravelly

Reputation: 3280

The static methods are called only once and once loaded those are not called again. It would be a deadlock if A.Initialize() method called B.Initialize() method and vice versa.

So any class first loaded into the memory the static block gets executed and after that any subsequent called to it - because the class is already loaded so static block doesn't get executed.

Upvotes: 0

Related Questions