44

オブジェクトがロックされているかどうかを検出するにはどうすればよいですか?

Monitor.TryEnterオブジェクトがロックされているかどうかを検出する方法はありますか?で説明されているように)ロックされていない場合はオブジェクトがロックされるため、機能しません。

ロックされているかどうかだけを確認したいので、コード内のどこかでMonitorクラスを使用してオブジェクトをロックします。

たとえばブールフィールド(たとえばprivate bool ObjectIsLocked)を使用することは可能ですが、lock-object自体を使用してそれを検出する方法はわかっています。

以下のサンプルコードは、私がやりたいことを示しています。

private static object myLockObject = new object();

private void SampleMethod()
{
    if(myLockObject /*is not locked*/) // First check without locking it
    {
        ...
        // The object will be locked some later in the code
        if(!Monitor.TryEnter(myLockObject)) return;

        try
        {

            ....
        }
        catch(){...}
        finally
        {
            Monitor.Exit(myLockObject);
        }
    }
}
4

6 に答える 6

54

あなたはそれを間違っています。オブジェクトにロックがない場合、ロックされているかどうかを確認することはできません(ロックがある場合は、事前に知っておく必要があります)。あなたは「尋ねる」「ロックされていますか?」応答として「not」を取得すると、次のナノ秒で別のスレッドがロックを取得し、プログラムが破損した状態になります。これは単にマルチスレッドアプリを使用する方法ではなく、.NETにメソッドがない理由ですMonitor.IsLocked。コードがロックを取得する前にロックをチェックする必要がある場合は、設計上の問題があります。保護されていないフラグでそれを解決しようとすることは、100%の確率で機能しないことが保証されている貧弱な解決策です。

boolとにかく、マルチスレッドがロックされた状態であることを通知するためにvarを使用しないでください(同じ問題が発生する可能性があるため、「false」を読み取り、1ナノ秒後に別のスレッドが「true」を書き込みます)。を使用しInterlock.CompareExchangeます。

private static int _lockFlag = 0; // 0 - free

if (Interlocked.CompareExchange(ref _lockFlag, 1, 0) == 0){
   // only 1 thread will enter here without locking the object/put the
   // other threads to sleep.

   Monitor.Enter(yourLockObject); 

   // free the lock.
   Interlocked.Decrement(ref _lockFlag);
}

オブジェクトへのロックを取得できるすべての場所で_lockFlagを変更する必要があることがわかります。つまり、ネイティブのロックシステムを中心にカスタムロックシステムを構築します。

于 2012-08-20T22:53:07.697 に答える
11

C#のMonitorクラスでこれを行う方法はありません

使用するだけです。

    var lockedBySomeoneElse = !Monitor.TryEnter(obj);
    if (!lockedBySomeoneElse) Monitor.Exit(obj);
    // the variable 'lockedBySomeoneElse' has the info you want

readerwriterlockslimのような他のロックは実際には役に立ちません。それは読者がどのようにいるのかをあなたに伝えることができますが、忙しい作家がいる場合はそうではありません;-(

また、独自の提案「private bool ObjectIsLocked」を使用する場合は、これが私がたどるルートだと思います。

      private volatile bool ObjectIsLocked

これにより、C#はマルチスレッドの更新で変更をより適切に反映できるようになります。

于 2012-08-20T11:29:48.217 に答える
9

Monitor.IsEnteredでうまくいくはずです。

編集:ドキュメントを読み直したところ、次のように表示されます。

現在のスレッドが指定されたオブジェクトのロックを保持しているかどうかを判別します。

別のスレッドがロックを保持しているかどうかを知りたいので、それだけでは不十分ですか?

于 2012-08-20T07:39:07.270 に答える
0

オブジェクトが後でロック可能であることを確認したい場合はTryEnter、ロックをずっと呼び出して保持するだけです。それ以外の場合、後でオブジェクトをロックしようとする場合は、呼び出しTryEnterて、ロックされている場合はすぐにロックを解除します。

于 2012-08-20T07:36:15.320 に答える
0

技術的には、同期ブロック配列に関連する遅延割り当て構造のインデックスを持つオブジェクトの同期ブロックインデックスフィールドを確認できます。すべてのオブジェクトにこのフィールドがあり、同期に使用されるすべてのオブジェクトにこのフィールドが設定されています。これらの構造は、スレッドの同期を調整するために使用されます。ただし、プロファイリングAPIがなくてもこの情報にアクセスできるかどうかは非常に疑わしいです。

于 2012-08-20T07:57:54.960 に答える
-3

ロックをチェックしてからコードブロックを入力することを推奨することはできません。しかし、新しい関数がオブジェクトをロックしたままにできないことを確認する方法を探しているときに、このスレッドを見つけました。Monitor.IsEnteredに基づく単体テストにより、私が探していたものが正確に得られました。

于 2018-02-02T17:17:06.540 に答える