如何检测对象是否被锁定?
Monitor.TryEnter
(如有没有办法检测对象是否被锁定?中所述)对我不起作用,因为如果对象未锁定,它会锁定对象。
我only想检查它是否被锁定,并且在我的代码中的其他地方我将使用
Monitor
类来锁定对象。
我知道可以使用例如布尔字段(例如
private bool ObjectIsLocked
),但是使用锁定对象本身来检测它。
下面的示例代码显示了我想要做的事情:
private static object myLockObject = new object();
private void SampleMethod()
{
if(myLockObject /*is not locked*/) // First check without locking it
{
...
// The object will be locked some later in the code
if(!Monitor.TryEnter(myLockObject)) return;
try
{
....
}
catch(){...}
finally
{
Monitor.Exit(myLockObject);
}
}
}
你做错了。如果你没有对象上的锁,你就无法检查它是否被锁定(如果你有锁,你会提前知道)。你可以“问”“被锁了吗?”并得到“不”作为响应,然后在下一个纳秒另一个线程可以获取锁定,并且您的程序将处于损坏状态。这根本不是多线程应用程序的方式,也是 .NET 没有
Monitor.IsLocked
方法的原因。如果您的代码需要在获取锁之前检查锁,那么您就遇到了设计问题。尝试使用不受保护的标志来解决这个问题是一个糟糕的解决方案,100% 的可能性是行不通的。
无论如何,不要使用
bool
var 来表示多线程已锁定状态(因为您可能会遇到同样的问题,您读取“false”,1纳秒后另一个线程将向其写入“true”)。使用Interlock.CompareExchange
。
private static int _lockFlag = 0; // 0 - free
if (Interlocked.CompareExchange(ref _lockFlag, 1, 0) == 0){
// only 1 thread will enter here without locking the object/put the
// other threads to sleep.
Monitor.Enter(yourLockObject);
// free the lock.
Interlocked.Decrement(ref _lockFlag);
}
您会发现您需要在每个可以获取对象锁的地方更改_lockFlag。换句话说,您将围绕本机锁定系统构建一个自定义锁定系统。
C# 中的 Monitor 类无法做到这一点
只需使用;
var lockedBySomeoneElse = !Monitor.TryEnter(obj);
if (!lockedBySomeoneElse) Monitor.Exit(obj);
// the variable 'lockedBySomeoneElse' has the info you want
其他锁(例如 readerwriterlockslim)并没有真正的帮助。那个人可以告诉你有多少读者,但不能告诉你是否有一位作家很忙;-(
如果您使用自己的建议“private bool ObjectIsLocked”,这是我认为我会采取的路线,您应该使用
private volatile bool ObjectIsLocked
这将使 C# 通过多线程更新更好地反映对其的更改。
如果您想确保该对象稍后仍可锁定,只需调用
TryEnter
并始终保持锁定即可。否则,如果您想稍后尝试锁定该对象,只需调用 TryEnter
并在锁定时立即解锁。
从技术上讲,您可以检查对象的 Sync Block Index 字段,该字段具有 Sync Blocks array 中关联的延迟分配结构的索引 - 每个对象都有此字段,并且用于同步的每个对象都设置有此字段。这些结构用于协调线程同步。但是,我非常怀疑您是否能够在没有 Profiling API 的情况下访问此信息。
我绝不提倡检查锁然后输入代码块。然而,我在寻找一种方法来检查新函数不能锁定对象时发现了这个线程。基于 Monitor.IsEntered 的单元测试让我得到了我想要的东西。