【问题标题】:How to release a lock and acquire another atomicly如何以原子方式释放锁并获取另一个锁
【发布时间】:2011-08-04 02:19:46
【问题描述】:

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

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

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

我需要的是两条标记的行以原子方式执行。有没有办法做到这一点?

【问题讨论】:

  • 为什么不先拿锁再解锁经理?
  • 为什么不使用另一个锁。 makethisactionatomic 锁。
  • @CodeInChaos:如果其他锁被阻塞,那么第一个锁的释放也会在这段时间内被阻塞。
  • @dcarapic 你的管理器和对象锁应该是独立的,交换最后两行,如果你不能这样做,那么你可能在代码中有错误。请发布经理和对象的锁定和解锁代码。
  • @oleksii 交换两行并不是一个好的解决方案。如果 myLock 的锁定会阻塞,那么这也会阻塞 LockManager 的解锁,请求其他锁阻塞: LockManager.Lock(); var myLock = LockManager.FindLock(myObject); myLock.Lock(); // 如果因为锁已经被占用而阻塞 LockManager.Unlock(); // 那么这也会被阻塞

标签: c# .net multithreading


【解决方案1】:

所以你想:

  • 保证个人锁(通过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.
}

这将为您提供所需的原子性,但代价是操作不成功。如果您依赖此操作立即成功,那么您将不得不重新考虑您的整体设计。

【讨论】:

    猜你喜欢
    • 2013-08-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-06-18
    • 2021-06-10
    • 2016-01-23
    • 1970-01-01
    相关资源
    最近更新 更多