web-dev-qa-db-ja.com

C#オブジェクトが既にロックされていることを検出する方法

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

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

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

たとえばブール値フィールド(たとえばprivate bool ObjectIsLocked)しかし、ロックオブジェクト自体を使用してそれを検出するもの。

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

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);
        }
    }
}
31
hwcverwe

あなたは間違っている。オブジェクトにロックがない場合は、ロックされているかどうかを確認できません(ロックがある場合は、事前に知ることができます)。 「質問」「ロックされていますか?」応答として「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をオブジェクトのロックを取得できるすべての場所で変更する必要があることがわかります。つまり、ネイティブロックシステムを中心にカスタムロックシステムを構築します。

44
Marcelo De Zen

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

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

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

あなたはおそらく別のスレッドがロックを保持しているかどうかを知りたいので、それは十分ではありませんか?

8
Pete

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#に対する変更がより適切に反映されます。

5
IvoTops

技術的には、オブジェクトの同期ブロックインデックスフィールドをチェックできます。このフィールドには、関連する遅延割り当て構造のインデックスがあります同期ブロックアレイ-すべてのオブジェクトには、このフィールドと、同期、このフィールドが設定されています。これらの構造は、スレッドの同期を調整するために使用されます。ただし、Profiling APIなしでこの情報にアクセスできることを非常に疑います。

0
Andrey Taptunov

オブジェクトを後でロックできるようにしたい場合は、TryEnterを呼び出して、ロックを保持するだけです。そうでない場合、後でオブジェクトをロックしようとする場合は、TryEnterを呼び出して、ロックされている場合はすぐにロックを解除します。

0
David Schwartz