如何释放一个锁并自动获取另一个锁
本文关键字:获取 另一个 何释放 释放 一个 | 更新日期: 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.
}
这将为您提供您正在寻找的原子性,但代价是操作不成功。如果你指望这个操作立即成功,那么你将不得不重新考虑你的整体设计。