web-dev-qa-db-ja.com

同じオブジェクトをロックしないとデッドロックが発生しないのはなぜですか?

可能性のある複製:
C#の再入可能ロック

このようなコードを書いた場合:

class Program {
    static void Main(string[] args) {
        Foo();
        Console.ReadLine();
    }

    static void Foo() {
        lock(_lock) {
            Console.WriteLine("Foo");
            Bar();
        }
    }

    static void Bar() {
        lock(_lock) {
            Console.WriteLine("Bar");
        }
    }

    private static readonly object _lock = new object();
}

私は出力として取得します:

Foo
Bar

Fooがロックを取得し、Barがロックを取得するまで待機するため、これはデッドロックになると予想していました。しかし、これは起こりません。

コードが同じスレッドで実行されるため、ロックメカニズムはこれを単純に許可しますか?

55
Eric

同じスレッドの場合、ロックは常に 再入可能 であるため、スレッドはオブジェクトを必要なだけロックできます。

77
thumbmunkeys

ここにはスレッドが1つしかないからです。

lock

bool lockWasTaken = false;
var temp = obj;
try { 
       Monitor.Enter(temp, ref lockWasTaken); 
       // your thread safe code
}
finally { if (lockWasTaken) Monitor.Exit(temp); }

Monitor.Enter パラメータとして渡されたオブジェクトのモニターを取得します。別のスレッドがオブジェクトに対してEnterを実行したが、対応するExitをまだ実行していない場合、現在のスレッドは、他のスレッドがオブジェクトを解放するまでブロックします。 同じスレッドがブロックせずにEnterを複数回呼び出すことは合法です;ただし、オブジェクトで待機している他のスレッドのブロックが解除される前に、同数のExit呼び出しを呼び出す必要があります。

21

1つの単語:再入可能ロック。スレッドがすでにロックを取得している場合は、再度ロックを取得する必要があるかどうかを待機しません。これは非常に必要です。さもなければ、単純な再帰関数を悪夢に変える可能性があります。

9
pathfinder666

lockステートメントはそれよりも賢く、これだけを防ぐように設計されています。ロックは、スレッド内に入るとスレッドが「所有」するため、同じオブジェクトをロックする別のlockステートメントに到達すると、そのロックにすでにアクセスしていることがわかります。

5
Servy