所以你的原因不要想要在析構函數中使用鎖定是因爲析構函數可能在Final語句線程中由FinalizerWorker調用,同時在所有線程上停止執行。
因此,如果一個線程在FinalizerWorker啓動時處於ConcurrencyDicitonary操作的中間,那麼如果析構函數嘗試鎖定ConcurrencyDictionary(這可能很難重現死鎖),則可能會死鎖。
自旋鎖不會幫助你,因爲如果任何當前正在執行的線程具有ConcurrencyDictionary鎖定或微調可變鎖定它不會釋放,直到FinalizerWorker完成,它不會因爲它會旋轉/永遠鎖定。
您在這裏的主要選項是通過SuppressFinalize(this)調用實現IDisposable接口,因爲您的對象將抑制Finalizer worker,所以不會發生死鎖並且ConcurrencyDictionary操作是安全的!
因此,如果您使用object.Dispose搶先終結(),你應該是安全的使用ConcurrencyDictionary,但在其他方面不要使用任何類型的鎖,你終結的Dispose(假)調用,或者你會在某個時候發生死鎖。
// Design pattern for a base class.
public class Base: IDisposable
{
private bool disposed = false;
//Implement IDisposable.
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
protected virtual void Dispose(bool disposing)
{
if (!disposed)
{
//Disposing outside the FinalizerWorker (SAFE)
if (disposing)
m_pDictionary.TryRemove(this);
disposed = true;
}
}
// Use C# destructor syntax for finalization code.
~Base()
{
// Simply call Dispose(false).
Dispose (false);
}
謝謝,我很害怕這個。你能否提出一些解決方法?一種可能是使用'Interlocked'來設置一個標誌,該標誌需要清除集合,然後在每個公共方法中爲該標誌設置'CompareExchange',但這不是很乾淨的解決方案。我能否使用一些愚蠢的行爲,比如在析構函數中啓動一個線程來清理GC完成後的集合?我不確定直到GC完成或者它們是否同時運行,從析構函數開始的線程是否處於掛起狀態。 – Paya 2015-03-19 04:13:04
更新建議使用線程池來刪除項目。 – 2015-03-19 04:24:57
因此,如果我在線程池('Task.Factory.StartNew',或者除'new Thread()')之外的其他任務上安排任務,那麼線程將在所有垃圾收集完成後開始?我擔心通過在終結器中啓動任何類型的線程,該線程可能與終結線程同時運行。也許這種情況發生,當我在'Wrapper'終結器中時,字典也被垃圾收集,因此,啓動一個新線程來對正在收集的集合進行清理可能不是一個好主意。 – Paya 2015-03-19 04:47:12