web-dev-qa-db-ja.com

C#ロックが待機する時間と、ロック中にコードがクラッシュした場合はどうなりますか?

私は次のコードを見ましたが、一度に1つしか実行されず、頻繁には発生しない単純なアクティビティに使用したかったので(一度に2回発生する可能性は非常に小さいですが、あなたは決して知りません)。

だからコード:

_ //class variable
    private static object syncRoot = new object();

    //in a method:
    lock (syncRoot)
    {
     DoIt();
    }
_

別のスレッドが来てコードを実行したい場合、ロックが解除されるまでどれくらいの時間待機しますか?永遠に、または何らかの形でタイムアウトを設定できますか?

2番目:DoIt()メソッドが例外をスローした場合、ロックはまだ解除されていますか?

46
Michel

別のスレッドが来てコードを実行したい場合、ロックが解除されるまでどれくらいの時間待機しますか?

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); }
_

例外がスローされたときに何が起きるかについての詳細な詳細については、 ロックと例外が混在しない を参照してください。

74
jason

前述のように、通常のロックは永久に待機するため、デッドロックのリスクがあります。

推奨されるメカニズムは次のとおりです(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(適切な実装に存在する)により、エラー状態でもロックが解除されます。

32
Marc Gravell

単純なlock(syncRoot)は永遠に待機します。

に置き換えることができます

_if (System.Threading.Monitor.TryEnter(syncRoot, 1000))
{
     try
     {
         DoIt();
     }
     finally
     {
         System.Threading.Monitor.Exit(syncRoot);
     }
}
_

すべてのスレッドは、例外セーフロックを保証する必要があります。

標準のlock(syncRoot) {}Monitor.Enter(syncRoot)とtry/finallyに書き換えられることに注意してください

9
Henk Holterman

ヘンクが言ったように、ロックは永遠に待機します。例外は引き続きロック解除されます。 try-finallyブロックで内部的に実装されます。

3
Mr47

Monitor you EnterExitedである場合に、一歩下がって、メソッドから例外を発言させる理由を自問する必要があります。 DoIt()が例外をスローする可能性さえある場合(そして、可能であればDoIt()を書き直して、DoesNotにしないと主張します)、try/catch lock()ステートメント内でブロックして、必要なクリーンアップを確実に実行できるようにします。

1
dlev

デッドロックが発生するために必要な前提条件を知る。デッドロックを回避するために、常にMonitor vs Lockを使用してください。

Conditions

0
dot.net5000