C#如何检测对象已被锁定

时间:2012-08-20 07:27:20

标签: c# multithreading .net-4.0 locking

如何检测物体是否被锁定?

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

6 个答案:

答案 0 :(得分:43)

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

无论如何,不​​要使用bool var来表示多线程被锁定状态(因为你可能有同样的问题,你读“假”和1纳秒后来另一个线程会写“真”到它)。使用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,可以获取对象的锁定。换句话说,您将围绕本机锁定系统构建一个自定义锁定系统。

答案 1 :(得分:8)

Monitor.IsEntered应该可以做到这一点。

编辑:我只是重新阅读文档,并说:

  

确定当前线程是否持有指定的锁   对象

所以这还不够,因为你可能想知道一个不同的线程是否持有锁?

答案 2 :(得分:5)

使用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#更好地反映对多线程更新的更改。

答案 3 :(得分:0)

如果您想确保以后对象仍然可以锁定,只需调用TryEnter并一直保持锁定。否则,如果您想稍后尝试锁定对象,只需致电TryEnter并在锁定时立即解锁。

答案 4 :(得分:0)

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

答案 5 :(得分:-1)

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