web-dev-qa-db-ja.com

C#の再入可能ロック

次のコードは、.NETでC#を使用してデッドロックになりますか?

 class MyClass
 {
    private object lockObj = new object();

    public void Foo()
    {
        lock(lockObj)
        { 
             Bar();
        }
    }

    public void Bar()
    {
        lock(lockObj)
        { 
          // Do something 
        }
    }       
 }
112
Guy

いいえ、同じオブジェクトをロックしている限りではありません。効果的な再帰コードはすでにロックを持っているため、妨げられることなく続行できます。

lock(object) {...}は、 Monitor クラスを使用するための略記です。 Marcが指摘しているようにMonitorre-entrancyを許可するため、繰り返し試行されます現在のスレッドが既にロックを持っているオブジェクトをロックするにはうまくいきます。

differentオブジェクトでロックを開始する場合は、注意する必要があります。特に注意してください:

  • 同じシーケンス内の指定された数のオブジェクトに対して常にロックを取得します。
  • 常にreverseシーケンスでロックを解除し、ロックを取得します。

これらのルールのいずれかを破ると、デッドロックの問題が発生することがほぼ確実になりますある時点で

.NETでのスレッドの同期について説明する1つの優れたWebページを次に示します。 http://dotnetdebug.ne​​t/2005/07/20/monitor-class-avoiding-deadlocks/

また、できるだけ少ないオブジェクトを一度にロックします。可能な場合は、 粗粒度ロック の適用を検討してください。オブジェクトグラフがあるようにコードを記述でき、そのオブジェクトグラフのルートでロックを取得できる場合は、そうするという考え方です。これは、そのルートオブジェクトに1つのロックがあるため、ロックを取得/解放するシーケンスについてそれほど心配する必要がないことを意味します。

(さらに注意してください、あなたの例は技術的に再帰的ではありません。再帰的であるために、Bar()はそれ自体を、通常は反復の一部として呼び出す必要があります。)

140
Neil Barnwell

Monitorは再入可能ですので、自分でデッドロックすることはできません...だからいいえ:すべきではありません

19
Marc Gravell

スレッドがすでにロックを保持している場合、スレッドはそれ自体をブロックしません。 .Netフレームワークはこれを保証します。 2つのスレッドが、コードパスに関係なく同じ2つのロックを取得しようとしないことを確認するだけです。

同じスレッドは同じロックを複数回取得できますが、ロックを取得した回数と同じ回数だけロックを解除する必要があります。もちろん、これを達成するために「ロック」キーワードを使用している限り、自動的に実行されます。

6

いいえ、このコードにはデッドロックはありません。本当に簡単にデッドロックを作成したい場合は、少なくとも2つのリソースが必要です。犬と骨のシナリオを検討してください。 1.犬は1つの骨を完全に制御できるため、他の犬は待つ必要があります。 2.骨をそれぞれロックし、他の骨を探すときにデッドロックを作成するには、2つの骨を持つ2匹の犬が最低限必要です。

..などn犬とm骨などにより、より洗練されたデッドロックが発生します。

5
Rishabh Jain