10

それで、私はエリック・リッパートからこれを喜んで読んでいました、そしてもちろん、ジョン・ペイソンが言った素晴らしいコメントを読んでいました:

より興味深い例は、2 つの静的クラスを使用することでした。そのようなプログラムは、目に見えるブロッキング ステートメントがなくてもデッドロックする可能性があるからです。

ええ、それは簡単だと思ったので、これをノックアップしました:

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

( を呼び出した後のB.Go())出力は次のとおりです。

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

行き詰まりはなく、私は明らかに敗者です - 恥ずかしさを永続させるために、ここに私の質問があります: なぜここで行き詰まりがないのですか?

の静的コンストラクターが終了する前B.Initializeに呼び出されるのは私の小さな脳には思えますが、それは許可されていないと思いました。B

4

5 に答える 5

6

ブロックする必要のあることも、中断する必要のあることもしていないため、デッドロックではありません。

A内のリソースを使用していませんB。その逆も同様です。その結果、何も爆発しないという意味で、循環依存は「安全」です。

印刷物が示すパスをトレースすると、何もブロックされません。

  1. 電話するGo(疑う)
  2. B初期化されていないため、 (staticコンストラクター)を入力します。
  3. プリントアウト
  4. 使用するA.Initialize()
  5. Astaticコンストラクターを最初に実行する必要があります
  6. プリントアウト
  7. 使用するB.Initialize()
  8. B初期化する必要はありませんが、完了した状態ではありません(幸い、変数は設定されていないため、何も壊れません)
  9. プリントアウトして返却
  10. (Astaticコンストラクターから) 出力してから戻ります
  11. A.Initialize()は初期化されているため、最終的に呼び出すことAができます
  12. プリントアウトして返却
  13. (Bstaticコンストラクターから) 出力してから戻ります
  14. Go

あなたが実際に行った唯一のことは、危険な状態の可能性を提示したことです: コンストラクターの実行が完了していないクラスへのアクセスです。これは安全でないコードであり、ブロックしていませんが、間違いなく壊れた状態を表しています。

于 2013-02-01T07:31:39.610 に答える
1

重要な点は、関連するスレッドが 1 つだけであるということです。ブログ投稿からの引用:

次に、静的コンストラクターが新しいスレッドを開始します。そのスレッドが開始されると、CLR は、静的コンストラクターが "飛行中"の別のスレッドである型で静的メソッドが呼び出されようとしていることを認識します。メイン スレッドがクラス コンストラクターの実行を終了するまで Initialize メソッドが開始されないように、新しいスレッドを直ちにブロックします。

Erics の例では、互いに待機している 2 つのスレッドがあります。スレッドは 1 つしかないため、待機は発生せず、その結果、ブロックもデッドロックも発生しません。

于 2013-02-01T07:32:21.860 に答える
1

デッドロックが必要だと考える理由。静的コンストラクターは 1 回だけ呼び出されます。ステートメントを何回実行しB.Initialize();ても、クラス B の静的コンストラクターは、B が参照されたときに初めて呼び出されます。静的コンストラクターの詳細については、こちらを参照してください

于 2013-02-01T07:40:56.517 に答える
0

静的メソッドは1回だけ呼び出され、ロードされると再度呼び出されることはありません。A.Initialize()メソッドがメソッドと呼ばれるB.Initialize()場合、またはその逆の場合、デッドロックになります 。

したがって、最初に静的ブロックがメモリにロードされたクラスが実行され、その後、クラスが呼び出されます。これは、クラスがすでにロードされているため、静的ブロックが実行されないためです。

于 2013-02-01T07:20:13.487 に答える
-3

クラス インスタンスは実際にはコンストラクター呼び出しの前に作成されるため、コンストラクターを実行する必要はもうありません。

于 2013-02-01T07:28:41.700 に答える