4
class Program
{
    static object test = new object();
    static void Main(string[] args)
    {
        new Program().test2();
        Console.ReadKey();
    }

    public void test1()
    {
        lock (test)
        {
            Console.WriteLine("test1");
        }
    }

    public void test2()
    {
        lock (test)
        {
            test1();
            Console.WriteLine("test2");
        }
    }
}

上記のコードは、最初にtest2()のlockステートメントのステートメントを終了してからtest1()に移動することになっていますか?(つまり、出力は次のようになっているはずではありませんか?:test2 test1)

4

3 に答える 3

15

いいえ。イベントのシーケンス(インデントはコールスタックまたは論理演算を表します)は次のとおりです。

  • 主な呼び出しtest2
    • test2は、テストオブジェクトに関連付けられたモニターの取得を試みます(lockステートメントの開始)
      • モニターは現在所有されていません。成功!
      • 現在のスレッドは、そのモニターを1カウントで「所有」しています。
    • test2はtest1を呼び出します
      • test1は、テストオブジェクトのモニターを取得しようとします(lockステートメントの開始)
        • モニターは現在所有されています...しかし現在のスレッドによって所有されています。成功!
        • 現在のスレッドはまだモニターを「所有」しており、カウントは2です。
      • test1は「test1」を出力します
      • test1はモニターを解放します(lockステートメントの終わり)
        • 現在のスレッドはまだモニターを「所有」しており、カウントは1です。
      • test1は
    • test2は「test2」を出力します
    • test2はモニターを解放します(lockステートメントの終わり)
      • モニターは現在所有されていません(別のスレッドがモニターを取得できるように)
    • test2は

モニターは再入可能であることに注意することが重要です。現在のスレッドが既にモニターを所有している場合、モニターを取得しようとすると、ブロックするのではなく、カウントが増えるだけです。

モニター再入可能でない場合、出力は「test2、test1」ではなく、デッドロックになります。

于 2012-06-30T08:22:21.487 に答える
11

モニターは同じスレッドで再入可能です。偶発的なデッドロックを回避するために非常に重要です。そのような動作がない場合、コードは確実にフリーズします。

ミューテックスも再入可能ですが、セマフォは再入可能ではありません。

実装は非常に簡単です。モニターは2つの情報を保存します。入力されたスレッドの所有者Thread.ManagedIdと、入力された回数をカウントするカウンター。したがって、最初のロックは所有されていないため入ることができ、所有者をスレッドに設定し、カウントを1に設定します。スレッドIDが一致するため、2番目のロックは入ることができ、カウントは2に増加します。 2番目のロックでは、カウントが再び1に減少します。最初の最後に、カウントが0に減少し、所有者がリセットされます。

于 2012-06-30T08:24:24.060 に答える
2

ロックは、シングルスレッドのシナリオでは使用されません。その目的は、同じメソッドまたはオブジェクトインスタンスへのクロススレッド呼び出しで使用されることです。

あなたが気づいている振る舞いは正常です。

通常、2つ以上のスレッドが同時にリソースにアクセスできる場合は、リソース(変数、コレクションなど)へのアクセスを同期する必要があります。

于 2012-06-30T08:22:34.253 に答える