2017-01-17 31 views
2

我有一点很难解释的奇怪问题。我有singleton类,在构造函数中我必须运行一个任务来初始化一些组件/资源。Singleton - 构造函数中的任务无法启动/不能异步启动

我从的C#深度使用了2个单身人士的执行情况,在一种情况下一切正常,在另一种情况下工作正常 - 不是。

代码在下面有一些评论。 由于某种原因,任务在一种情况下不会启动,主要问题是当我使用具有初始化和静态构造函数的静态字段(类Test2)时。

我做了一些其他测试,看起来像实现2任务不是以异步方式启动,而是在等待时间后同步启动。

执行一个。一切工作按预期

public sealed class Test1 
{ 
    private static Test1 instance = null; 
    private static readonly object padlock = new object(); 

    private Test1() 
    { 
     using (AutoResetEvent startEvent = new AutoResetEvent(false)) 
     { 
      new Task(() => TaskThread(startEvent)).Start(); 

      if (!startEvent.WaitOne(1000)) 
      { 
       throw new Exception("ERROR"); 
      } 
     } 
    } 

    public int Result() 
    { 
     return 10; 
    } 

    private void TaskThread(AutoResetEvent startEvent) 
    { 
     //I am initializing some stuff here 
     startEvent.Set(); 
    } 

    public static Test1 Instance 
    { 
     get 
     { 
      lock (padlock) 
      { 
       if (instance == null) 
       { 
        instance = new Test1(); 
       } 
       return instance; 
      } 
     } 
    } 
} 

实施2,任务从未启动,或者等待时间事件的

public sealed class Test2 
{ 
    private static readonly Test2 instance = new Test2(); 

    static Test2() 
    { 
    } 
    private Test2() 
    { 
     using (AutoResetEvent startEvent = new AutoResetEvent(false)) 
     { 
      new Task(() => TaskThread(startEvent)).Start(); 

      //here it fails to wait successfully and throws an 
      //exception. Time limit is not reached 
      if (!startEvent.WaitOne(1000)) 
      { 
       throw new Exception("ERROR"); 
      } 
     } 
    } 

    public int Result() 
    { 
     return 20; 
    } 

    private void TaskThread(AutoResetEvent startEvent) 
    { 
     //I am initializing some stuff here as well 
     //but in this implementation code is never reached 
     startEvent.Set(); 
    } 

    public static Test2 Instance 
    { 
     get 
     { 
      return instance; 
     } 
    } 
} 

我很好奇,为什么会出现这种情况,以及如何避免在未来的这个问题后开始。非常感谢!

+0

我认为它可能在静态字段初始化期间是因为'System.TypeInitializer'。 –

+0

@ m.rogalski你能解释一下吗? –

+0

System.TypeInitializer在静态初始化过程中初始化某些类时遇到问题。顺序是首先初始化静态类型,然后是静态成员,然后调用入口点。也许在静态初始化期间,'TypeInitializer'没有关于特定类型的信息? –

回答

2

这种“奇怪”行为的根本原因很简单 - CLR在锁下执行静态构造函数。这可以防止创建的线程输入TaskThread()方法并将startEvent设置为发信号状态。

后,您面对几个小时为什么会发生这样的问题和困扰,你开始明白为什么很多来源建议不要用怀疑的结构,如静态构造函数,全局变量等

+0

非常感谢! 而对于其他人来这里 - 这里是关于这个主题的一些额外的信息 https://blogs.msdn.microsoft.com/pfxteam/2011/05/03/static-constructor-deadlocks/ –

+2

静态构造函数不是可疑的。令人怀疑的是在静态构造函数中启动一个线程/任务。 – VMAtm