44

如何检测对象是否被锁定?

Monitor.TryEnter(如Is there a way to detect if an object is locked?中所述)对我不起作用,因为如果对象未锁定,它会锁定该对象。

只想检查它是否被锁定,并且在我的代码中的其他地方我将使用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);
        }
    }
}
4

6 回答 6

54

你做错了。如果您没有锁定对象,则无法检查它是否已锁定(如果您有锁定,您会提前知道)。你可以“问”“被锁了吗?” 并得到一个“不”作为响应,然后在下一纳秒另一个线程可以获取锁,您的程序将进入损坏状态。这根本不是多线程应用程序的方式,也是 .NET 没有Monitor.IsLocked方法的原因。如果您的代码需要在获取锁之前检查锁,那么您就有设计问题。试图用不受保护的标志来解决它是一个糟糕的解决方案,它保证 100% 的机会不会起作用。

无论如何,不​​要使用boolvar 来表示多线程处于锁定状态(因为您可能遇到相同的问题,您读取“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

从技术上讲,您可以检查对象的同步块索引字段,该字段在同步块数组中具有关联的延迟分配结构的索引- 每个对象都有这个字段,每个用于同步的对象都有这个字段集。这些结构用于协调线程同步。但是,我非常怀疑您是否能够在没有Profiling API的情况下访问这些信息。

于 2012-08-20T07:57:54.960 回答
-3

我绝不提倡先检查锁然后输入代码块。但是,我在寻找一种方法来检查新函数无法锁定对象时发现了这个线程。基于 Monitor.IsEntered 的单元测试让我得到了我想要的东西。

于 2018-02-02T17:17:06.540 回答