順序をロックするには、逆の順序のロックを解除する必要があることを学びました。例えば。
A.lock();
B.lock();
B.unlock();
A.unlock();
しかし、私がこれを好きだったらどうなりますか:
A.lock();
B.lock();
A.unlock();
B.unlock();
デッドロックシナリオを作成しようとしましたが、常にAをBよりも早くロックすると、デッドロックがどのように発生するかわかりません。手伝ってくれませんか?
ロックの順序は、固定された順序でロックを取得することでデッドロックを防ぎ、ロック解除を開始した後にロックを再度取得しないことを意味します。
ここでは、ロック解除の順序に違いはないと思います(実際、順序が狂っていても、できるだけ早くロックを解除することが有益なはずです)。
与えられた単純なケースでは、デッドロックを回避するために逆の順序でロックを解除する必要はありません。
ただし、コードがより複雑になると、逆の順序でロックを解除すると、適切なロックの順序を維持するのに役立ちます。
考えてみましょう:
_A.lock();
B.lock();
Foo();
A.unlock();
Bar();
B.unlock();
_
Bar()
がAを再取得しようとすると、ロックの順序が事実上破られています。あなたはBを持っていて、それからAを取得しようとしています。今それはcanデッドロックです。
逆順スタイルでロックを解除する場合(RAIIを使用する場合は非常に自然です):
_A.lock();
B.lock();
Foo();
B.unlock();
Bar();
A.unlock();
_
その場合、Bar()
がロックを取得しようとしても、ロックの順序は保持されるため、問題ではありません。
あなたの例は、それ自体でデッドロックすることはありません。逆の順序でロックを解除することは重要ではありません。一貫した順序でロックします。ロック解除の順序が逆であっても、これはデッドロックになります
Thread 1
A.lock();
B.lock();
B.unlock();
A.unlock();
Thread 2
B.lock();
A.lock();
A.unlock();
B.unlock();
ここでデッドロックが発生するとは思わない。一般的なデッドロックの概念は、1つのスレッドが他のスレッドによってロックされたリソースを待機する一方で、他のスレッドは最初のスレッドによってロックされたリソースを終了して、最初に必要なリソースを解放する必要があるというものです。
ロック解除の順序は、システムがデッドロックする傾向に影響しませんが、ロック解除の順序について考える理由が1つあります。
デッドロックを回避するには、必須ロック解除がペアになっていることを確認してください。ロック解除を見逃すことはありません。文体的なアプローチとして、特定のロックの原因となるコードのブロックを目立つように配置することで、ロックとロック解除がペアになっていることを視覚的に簡単に識別できます。最終的な効果は、明らかに正しいコードが、説明したとおりにロックを取得して解放することです。
また、Javaの場合、synchronized
キーワードがロックに使用されている場合、ロック解除は逆の順序になります。 synchronized
キーワードを使用するために別の順序でロックを解除する方法はありません。
synchronized(a) {
synchronized(b) {
// statements
}
}
> lock(B)
> ---------- lock(C)
> ---------- lock(B) >>>> would block here
> ---------- release(B)
> ---------- release(C)
> lock(C) >>>>>> would block here
> release(B)
> release(C)
彼らの答えは素晴らしいです。これは、順序付けられていないロックと解放が実行された場合にデッドロックが発生する可能性がある別の状況です。一言、順序付けられていないリリースとロック共有リソース管理とクリティカルゾーンの設計に使用した仮定を破ります。