Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Do static constructors run as CERs?

I'm testing the below code:

private static void Main()
{
    var t = new Thread(() => 
    {
        var m = new MyCls();
        m.DoWork();       
    });
    t.Start();

    // simulate time-consuming job
    Thread.Sleep(1000);

    t.Abort();
    Console.Write("\nDone");
}


public class MyCls
{
    static MyCls()
    {
        for (int i = 0; i < 10; i++)
        {
            Console.Write(i);
            Thread.Sleep(1000);
        } 
    }

    public void DoWork()
    {
        Console.WriteLine("executing DoWork..");
    }
}

And the output I get is:

0123456789
Done

It seems that t.Abort() call is blocking the main thread until the execution of the static constructor finishes, and according to the documentation:

The thread that calls Abort might block if the thread that is being aborted is in a protected region of code, such as a catch block, finally block, or constrained execution region.

My questions is:

  1. Do static constructors really run as constrained execution regions (CERs) ?
  2. If yes, what other code blocks that run as CERs ?
like image 288
KeyBored Avatar asked Mar 05 '26 19:03

KeyBored


1 Answers

It seems that static constructors are guaranteed to have completed, almost.

Static constructors can be called explicitly with RuntimeHelpers.RunClassConstructor which 'Ensures that the type initializer (also known as a static constructor) for the specified type has been run'.

In your example, the code could be written as follows.

var t = new Thread(() =>
{
  System.Runtime.CompilerServices.RuntimeHelpers.RunClassConstructor(typeof(MyCls).TypeHandle);
  var m = new MyCls();
});

RunClassConstructor calls _RunClassConstructor which is annotated with the following comment.

In the absence of class constructor deadlock conditions, the call is further guaranteed to have completed.

// RunClassConstructor causes the class constructor for the given type to be triggered
// in the current domain.  After this call returns, the class constructor is guaranteed to
// have at least been started by some thread.  In the absence of class constructor
// deadlock conditions, the call is further guaranteed to have completed.
//
// This call will generate an exception if the specified class constructor threw an 
// exception when it ran. 
[System.Security.SecuritySafeCritical]
[ResourceExposure(ResourceScope.None)]
[MethodImplAttribute(MethodImplOptions.InternalCall)]
private static extern void _RunClassConstructor(RuntimeType type);
like image 178
tymtam Avatar answered Mar 07 '26 08:03

tymtam



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!