如何释放一个锁并自动获取另一个锁

本文关键字:获取 另一个 何释放 释放 一个 | 更新日期: 2023-09-27 18:04:34

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

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

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

我需要的是自动执行标记的两行。有办法做到这一点吗?

如何释放一个锁并自动获取另一个锁

所以你想:

  • 保证单个锁(通过myLock)被进入
  • 然后解锁LockManager
  • 使以上两个操作原子化
  • ,如果不能立即进入单个锁,则不允许这个新的原子操作阻塞

就像你不能绕过物理定律来制造永动机一样,你也不能通过自动执行一系列操作来绕过计算定律,即使它的一个组成部分实际上可能会阻塞,它也不会阻塞。换句话说,在各个部分也完成之前,没有办法使操作完成。

然而,我们能做的是以全或无的方式尝试这个原子操作,只要我们对"无"结果满意,就不会阻塞。对于存在于许多并发数据结构上的TryXXX方法,您经常会看到这种情况。您所需要做的就是在myLock类型上定义TryLock。然后,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.
}

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