2017-01-17 7 views
2

私は説明が難しい奇妙な問題があります。私はコンストラクタでいくつかのコンポーネント/リソースを初期化するタスクを実行する必要があるシングルトンクラスを持っています。シングルトン - コンストラクタ内のタスクが開始に失敗/非同期に開始しない

C#深度からのシングルトンの実装を2つ使用しています。あるケースではすべて正常に動作しています。別のケースではそうではありません。

コードはいくつかのコメントとともに下記にあります。 何らかの理由でタスクが1つのケースで開始されない主な問題は、initialierとstaticコンストラクタ(クラスTest2)で静的フィールドを使用しているときです。

私はいくつかのテストを行い、の実装のように見えます。2タスクは非同期では開始されませんが、待ち時間の後に同期して開始されます。

実装1。すべてが実装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; 
      } 
     } 
    } 
} 

を期待通りに働いている、タスクが

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'は、静的初期化プロセス中にいくつかのクラスを初期化する際に問題があります。順序は、最初に静的型を初期化してから静的メンバーを初期化し、次にエントリポイントを呼び出すことです。 static初期化中に、 'TypeInitializer'は特定の型に関する情報を持っていませんか? –

答えて

2

このような「奇妙な」動作の根本原因は非常に簡単です.CLRはロックのもとで静的コンストラクタを実行します。これにより、作成されたスレッドはTaskThread()メソッドに入り、startEventをシグナル状態に設定しません。など

なぜこれが起こっているあなたは、いくつかの時間のためにこのような問題やパズルに直面した後、あなたは多くのソースが静的コンストラクタ、グローバル変数のような疑わしい構文を使用しないように助言する理由を理解するために開始し、

+0

ありがとう! ここに来た他の人のために - ここにこのトピックに関するいくつかの追加情報があります https://blogs.msdn.microsoft.com/pfxteam/2011/05/03/static-constructor-deadlocks/ –

+2

静的コンストラクタは疑わしい。ダウトフルは静的コンストラクタでスレッド/タスクを開始しています。 – VMAtm

関連する問題