如何释放锁并以原子方式获取另一个锁

时间:2011-08-03 08:21:13

标签: c# .net multithreading

在我的应用程序中,我管理了一系列锁,我需要序列化对某些对象的访问(每个对象都分配了一个锁)。这个锁(锁管理器)集合也需要以线程安全的方式进行维护(添加新锁/删除旧锁,因为需要序列化的新对象被添加/删除)。 该算法的工作原理如下:

LockManager.Lock();
var myLock = LockManager.FindLock(myObject);
LockManager.Unlock();                          // atomic
myLock.Lock();                                 // atomic

交换两行不是一个好方法。如果锁定myLock会阻止,那么这也会阻止LockManager解锁,从而阻止其他锁的请求。

我需要的是两条标记的行以原子方式执行。有没有办法实现这个目标?

1 个答案:

答案 0 :(得分:3)

所以你想:

  • 保证输入个人锁定(通过myLock
  • 然后解锁LockManager
  • 使上述两个操作成为原子
  • 并且如果无法立即输入单个锁,则不允许此新原子操作阻止

类似于你不能绕过物理定律来创造一个永动机,你也无法通过原子方式执行一系列操作来规避计算定律,即使它的一个成分能够阻止它,事实上,有望阻止。换句话说,在各个部分也完成之前,无法完成操作。

然而,我们所能做的就是以一种全有或全无的方式尝试这种原子操作,只要我们对“无”结果没问题,就永远不会阻止。使用许多并发数据结构中存在的TryXXX方法,您会看到很多。您需要做的就是在TryLock类型上定义myLock。然后,LockManager可能如下所示。

public class LockManager
{
  public bool TryEnterIndividualLock(object value)
  {
    Lock();
    try
    {
      var myLock = FindLock(value);
      if (myLock != null)
      {
        return myLock.TryLock();
      }
      return false;
    }
    finally
    {
      Unlock();
    }
  }  
}

然后调用代码如下所示:

while (!LockManager.TryEnterIndividualLock(myObject))
{
  // Do something else until the lock can be entered.
}

这将为您提供您正在寻找的原子性,但代价是操作没有成功。如果您依靠此操作立即成功,那么您将不得不重新考虑您的整体设计。