3

我正在测试以下代码:

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..");
    }
}

我得到的输出是:

0123456789
Done

似乎t.Abort()调用阻塞了主线程,直到静态构造函数的执行完成,并且根据文档

Abort如果正在中止的线程位于代码的受保护区域(例如 catch 块、finally 块或受约束的执行区域)中,则调用的线程可能会阻塞。

我的问题是:

  1. 静态构造函数真的作为受约束的执行区域 (CER) 运行吗?
  2. 如果是,还有哪些其他作为 CER 运行的代码块?
4

2 回答 2

1

似乎几乎可以保证静态构造函数已完成

可以显式调用静态构造函数RuntimeHelpers.RunClassConstructor,“确保指定类型的类型初始值设定项(也称为静态构造函数)已运行”

在您的示例中,代码可以编写如下。

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

RunClassConstructor_RunClassConstructor带有以下注释的调用。

在没有类构造函数死锁条件的情况下,进一步保证调用已经完成。

// 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);
于 2019-10-19T04:24:55.623 回答
0

更新:问题是关于t.Abort()阻塞,而不是中断,所以这个答案几乎不相关:)


Thread.Abort Method的文档明确指出 Abort 可能会中止静态构造函数。

当线程对自身调用 Abort 时,效果类似于抛出异常;ThreadAbortException 立即发生,结果是可预测的。但是,如果一个线程在另一个线程上调用 Abort,则中止会中断正在运行的任何代码。静态构造函数也有可能被中止。在极少数情况下,这可能会阻止在该应用程序域中创建该类的实例。

例如,调用 Thread.Abort 可能会阻止静态构造函数执行或阻止释放非托管资源。


虽然您的示例优雅地表明静态构造函数可能不会被中断,但不能保证这种行为。


更新

这是一个使用 Abort() 中断静态 ctor 的示例。

代码

public static void Main()
{
    Console.WriteLine($"START");
    var t = new Thread(() =>
    {
        var m = new MyCls();
    });
    Console.WriteLine($"t.Start");
    t.Start();

    Thread.Sleep(2000);
    Console.WriteLine($"Trying to create a new object");

    try
    {
        var m2 = new MyCls();

    }
    catch (Exception ex) { Console.WriteLine(ex); }
    Console.WriteLine("All done");
    Console.ReadLine();
}


public class MyCls
{
    static MyCls()
    {
        for (int i = 0; i < 10; i++)
        {
            if (i == 4)
            {
                Console.WriteLine($"sctor calling Abort on itself");
                Thread.CurrentThread.Abort();
            };
            Console.WriteLine($"sctor.{i}");
            Thread.Sleep(100);
        }
    }
}

输出

START
t.Start
sctor.0
sctor.1
sctor.2
sctor.3
sctor calling Abort on itself
Trying to create a new object
System.TypeInitializationException: The type initializer for 'MyCls' threw an exception. ---> System.Threading.ThreadAbortException: Thread was being aborted.
   at System.Threading.Thread.AbortInternal()
   at System.Threading.Thread.Abort()
   at Program.MyCls..cctor() in c:\users\letss\source\repos\ConsoleApp2\ConsoleApp2\Program.cs:line 42
   --- End of inner exception stack trace ---
   at Program.MyCls..ctor()
   at Program.Main() in c:\users\letss\source\repos\ConsoleApp2\ConsoleApp2\Program.cs:line 21
All done
于 2019-10-18T23:50:59.517 回答