Monitor.TryEnter / Monitor.Exit and SynchronizationLockExcep
本文关键字:Monitor SynchronizationLockExcep and TryEnter Exit | 更新日期: 2023-09-27 17:50:21
是否有可能检测到相同的线程是否试图释放锁?我们的代码中有很多地方看起来像:
try
{
try
{
if(!Monitor.TryEnter(obj, 2000))
{
throw new Exception("can not lock");
}
}
finally
{
Monitor.Exit(obj);
}
}
catch
{
//Log
}
上面的代码非常简化,实际上Enter和Exit语句位于自定义对象(锁管理器)中。问题是,在该结构中,我们在尝试"退出"时拥有SynchronizationLockException
,因为它看起来像未成功锁定的线程,最终试图释放。
所以问题是,我怎么能知道如果线程谁使监视器。退出是执行Monitor.Enter的同一个线程?
我想我可以使用CurrentThread。我想同步进入和退出,但我不确定它是否足够"安全"。
所以问题是,我怎么能知道如果线程谁使监视器。退出是执行Monitor.Enter的同一个线程?
据我所知,你不能轻易做到。你无法找出哪个线程拥有一个监视器。
然而,这只是一个编码问题—您应该更改代码,使它甚至不会在不应该释放监视器时尝试释放监视器。所以上面的代码可以重写为:if (!Monitor.TryEnter(obj, 2000))
{
throw new Exception(...);
}
try
{
// Presumably other code
}
finally
{
Monitor.Exit(obj);
}
或者更好,如果你正在使用。net 4,使用TryEnter
的过载,它接受一个ret
参数:
bool gotMonitor = false;
try
{
Monitor.TryEnter(obj, ref gotMonitor);
if (!gotMonitor)
{
throw new Exception(...);
}
// Presumably other code
}
finally
{
if (gotMonitor)
{
Monitor.Exit(obj);
}
}
就像你认为的那样,把Monitor的调用。try-catch中的Exit是' duty '(dirty?),这里有一个非常简单的想法,试图'take the duty away'。同一个线程的锁是可重入的,如果一个线程获得成功,在它释放之前,来自另一个线程的尝试将失败。所以你可以考虑像这样:
public void Exit(object key) {
if(!IsActive) {
return;
}
if(LockDictionary.ContainsKey(key)) {
var syncObject=LockDictionary[key];
if(Monitor.TryEnter(syncObject.SyncObject, 0)) {
SetLockExit(syncObject);
Monitor.Exit(syncObject.SyncObject);
Monitor.Exit(syncObject.SyncObject);
}
}
}
我们调用Monitor。退出两次,因为我们锁定了它两次,一次在代码外部,一次在这里。
我知道这是一个老问题,但这是我的答案。我会将try-finally结构移到if:
中try
{
if(Monitor.TryEnter(obj, 2000))
{
try
{
// code here
}
finally
{
Monitor.Exit(obj);
}
}
else
{
throw new Exception("Can't acquire lock");
}
}
catch
{
// log
}