C# 如何释放一个锁并获取另一个原子

C# 如何释放一个锁并获取另一个原子,c#,.net,multithreading,C#,.net,Multithreading,在我的应用程序中,我管理一组锁,我需要这些锁来序列化对某些对象的访问(每个对象都分配了一个锁)。此锁集合(锁管理器)还需要以线程安全的方式进行维护(添加新锁/删除需要序列化的新对象时删除旧锁)。 算法的工作原理如下: LockManager.Lock(); var myLock = LockManager.FindLock(myObject); LockManager.Unlock(); // atomic myLock.Lock();

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

LockManager.Lock();
var myLock = LockManager.FindLock(myObject);
LockManager.Unlock();                          // atomic
myLock.Lock();                                 // atomic
while (!LockManager.TryEnterIndividualLock(myObject))
{
  // Do something else until the lock can be entered.
}
交换两行不是一个好的解决方案。如果锁定
myLock
会被阻止,那么这也会阻止解锁
LockManager
请求其他锁来阻止

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

所以您想:

  • 确保已输入单个锁(通过
    myLock
  • 然后解锁锁管理器
  • 使上述两个操作原子化
  • 如果无法立即进入单个锁,则不允许此新的原子操作阻止
就像你不能绕过物理定律来创造一台永动机一样,你也不能通过原子方式执行一系列操作来绕过计算定律,即使其中一个组成部分实际上可能会被阻塞,它也不会阻塞。换句话说,在单个零件也完成之前,无法完成操作

然而,我们所能做的是,以一种全有或全无的方式尝试这个原子操作,只要我们对“无”的结果感到满意,它就永远不会阻塞。在许多并发数据结构上存在的
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();
    }
  }  
}
然后调用代码将如下所示:

LockManager.Lock();
var myLock = LockManager.FindLock(myObject);
LockManager.Unlock();                          // atomic
myLock.Lock();                                 // atomic
while (!LockManager.TryEnterIndividualLock(myObject))
{
  // Do something else until the lock can be entered.
}

这会给你想要的原子性,但代价是操作没有成功。如果您希望此操作立即成功,那么您将不得不重新考虑您的总体设计。

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