Monitor.TryEnter / Monitor.Exit和SynchronizationLockException

是否有可能检测到同一个线程是否试图释放锁定? 我们在代码中有很多地方看起来像:

try { try { if(!Monitor.TryEnter(obj, 2000)) { throw new Exception("can not lock"); } } finally { Monitor.Exit(obj); } } catch { //Log } 

上面的代码非常简化,实际上Enter和Exit语句位于自定义对象(lock manager)中。

问题是,在该结构中,我们在尝试“退出”时有SynchronizationLockException ,因为它看起来像是没有成功锁定的线程,试图最终释放。

所以问题是,我怎么知道创建Monitor.Exit的线程是否与Monitor.Enter的线程相同?
我以为我可以使用CurrentThread.Id同步进入和退出,但我不确定它是否“足够安全”。

正如你认为在try-catch中调用Monitor.Exit是’durty’(脏?),这是一个非常简单的想法,试图“把durty带走”。 锁是可重入的同一个线程,如果一个线程成功获取,在它释放之前,另一个线程的尝试将失败。 所以你可以考虑这样的事情:

 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.Exit两次,因为我们将它锁定两次,一次在代码外部,一次在这里。

所以问题是,我怎么知道创建Monitor.Exit的线程是否与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); } } 

我知道这是一个较老的问题,但无论如何,这是我的答案。 我会在if中移动try-finally结构:

 try { if(Monitor.TryEnter(obj, 2000)) { try { // code here } finally { Monitor.Exit(obj); } } else { throw new Exception("Can't acquire lock"); } } catch { // log }