C#锁等待多长时间,以及在锁期间代码崩溃怎么办?

我看到下面的代码,我想用它来做一个简单的活动,一次只能执行一个,不会经常发生(所以一次发生两次的机会非常小,但是你永远不会知道)。

所以代码:

//class variable private static object syncRoot = new object(); //in a method: lock (syncRoot) { DoIt(); } 

当另一个线程来到并且想要执行代码时,它将等待多长时间直到锁被释放? 永远,或者你能以某种方式设置超时?

第二:如果DoIt()方法抛出exception,锁是否仍然释放?

当另一个线程来到并且想要执行代码时,它将等待多长时间直到锁被释放?

lock将无限期地阻止试图进入锁的线程,直到被locking的对象被释放。

你可以不知怎的弄湿超时?

如果你需要指定一个超时时间,可以使用Monitor.TryEnter

 if(Monitor.TryEnter(obj, new TimeSpan(0, 0, 1))) { try { body } finally { Monitor.Exit(obj); } } 

如果DoIt()方法抛出exception,锁是否仍然释放?

是的, lock(obj) { body }被转换为

 bool lockWasTaken = false; var temp = obj; try { Monitor.Enter(temp, ref lockWasTaken); { body } } finally { if (lockWasTaken) Monitor.Exit(temp); } 

有关引发exception时可能发生的事情的详细信息,请参阅locking和exception不混合 。

如前所述,一个普通的锁将永远等待,这是一个死锁的风险。

首选机制是(并注意ref ):

 bool lockTaken = false; try { Monitor.TryEnter(lockObj, timeout, ref lockTaken); if(!lockTaken) throw new TimeoutException(); // or compensate // work here... } finally { if(lockTaken) Monitor.Exit(lockObj); } 

这避免了在某些边缘情况下不能释放锁的风险。

finally (存在于任何明智的实现中)确保即使在错误情况下锁也被释放。

一个简单的lock(syncRoot)将永远等待。

你可以用它来replace它

 if (System.Threading.Monitor.TryEnter(syncRoot, 1000)) { try { DoIt(); } finally { System.Threading.Monitor.Exit(syncRoot); } } 

每个线程都应该确保exception安全locking。

请注意,标准lock(syncRoot) {}被重写为Monitor.Enter(syncRoot)并尝试/最后

亨克说,锁将永远等待。 exception仍然会解锁。 它在try-finally块内部实现。

您应该退后一步,问自己为什么当您EnterMonitor Exit时,让方法的exception有任何说法。 如果甚至有可能DoIt()可能会抛出一个exception(如果可能的话,你会重新写DoIt()以使它不是),那么你应该在lock()语句中有一个try/catch块您可以确保您执行任何必要的清理。

知道发生死锁的必要先决条件。 始终使用Monitor vs Lock来避免死锁。

条件

Jason anwser非常好,这是一个简单的方法来包装它。

  private void LockWithTimeout(object p_oLock, int p_iTimeout, Action p_aAction) { Exception eLockException = null; bool bLockWasTaken = false; try { Monitor.TryEnter(p_oLock, p_iTimeout, ref bLockWasTaken); if (bLockWasTaken) p_aAction(); else throw new Exception("Timeout exceeded, unable to lock."); } catch (Exception ex) { // conserver l'exception eLockException = ex; } finally { // release le lock if (bLockWasTaken) Monitor.Exit(p_oLock); // relancer l'exception if (eLockException != null) throw new Exception("An exception occured during the lock proces.", eLockException); } } 

然后用这个方法:

  // ajouter à la liste des fiches à loader LockWithTimeout(m_lLoadingQueue, 3600, () => { m_lLoadingQueue.Add(p_efEcranFiche); });