私は次のコードを見ましたが、一度に1つしか実行されず、頻繁には発生しない単純なアクティビティに使用したかったので(一度に2回発生する可能性は非常に小さいですが、あなたは決して知りません)。
だからコード:
_ //class variable
private static object syncRoot = new object();
//in a method:
lock (syncRoot)
{
DoIt();
}
_
別のスレッドが来てコードを実行したい場合、ロックが解除されるまでどれくらいの時間待機しますか?永遠に、または何らかの形でタイムアウトを設定できますか?
2番目:DoIt()
メソッドが例外をスローした場合、ロックはまだ解除されていますか?
別のスレッドが来てコードを実行したい場合、ロックが解除されるまでどれくらいの時間待機しますか?
lock
は、ロックされているオブジェクトが解放されるまで、無期限にロックに入るスレッドをブロックします。
どういうわけかタイムアウトを濡らすことができますか?
タイムアウトを指定する必要がある場合は、 _Monitor.TryEnter
_ を使用します
_if(Monitor.TryEnter(obj, new TimeSpan(0, 0, 1))) {
try {
body
}
finally {
Monitor.Exit(obj);
}
}
_
doIt()メソッドが例外をスローした場合、ロックはまだ解放されていますか?
はい、lock(obj) { body }
はに変換されます
_bool lockWasTaken = false;
var temp = obj;
try { Monitor.Enter(temp, ref lockWasTaken); { body } }
finally { if (lockWasTaken) Monitor.Exit(temp); }
_
例外がスローされたときに何が起きるかについての詳細な詳細については、 ロックと例外が混在しない を参照してください。
前述のように、通常のロックは永久に待機するため、デッドロックのリスクがあります。
推奨されるメカニズムは次のとおりです(ref
に注意してください):
bool lockTaken = false;
try {
Monitor.TryEnter(lockObj, timeout, ref lockTaken);
if(!lockTaken) throw new TimeoutException(); // or compensate
// work here...
} finally {
if(lockTaken) Monitor.Exit(lockObj);
}
これにより、一部のエッジケースでロックを解除しないリスクを回避できます。
finally
(適切な実装に存在する)により、エラー状態でもロックが解除されます。
単純なlock(syncRoot)
は永遠に待機します。
に置き換えることができます
_if (System.Threading.Monitor.TryEnter(syncRoot, 1000))
{
try
{
DoIt();
}
finally
{
System.Threading.Monitor.Exit(syncRoot);
}
}
_
すべてのスレッドは、例外セーフロックを保証する必要があります。
標準のlock(syncRoot) {}
がMonitor.Enter(syncRoot)
とtry/finallyに書き換えられることに注意してください
ヘンクが言ったように、ロックは永遠に待機します。例外は引き続きロック解除されます。 try-finallyブロックで内部的に実装されます。
Monitor
you Enter
がExit
edである場合に、一歩下がって、メソッドから例外を発言させる理由を自問する必要があります。 DoIt()
が例外をスローする可能性さえある場合(そして、可能であればDoIt()
を書き直して、DoesNotにしないと主張します)、try/catch
lock()ステートメント内でブロックして、必要なクリーンアップを確実に実行できるようにします。