當我看看IDisposable
的示例實現時,我沒有發現任何線程安全的。爲什麼IDisposable
未實現線程安全? (相反,呼叫者有責任確保只有一個線程呼叫Dispose()
)。爲什麼我沒有看到IDisposable實現併發的任何實現?
回答
Brian Lambert寫了一篇博文,標題爲A simple and totally thread-safe implementation of IDisposable。
它包含以下實現:
using System;
using System.Threading;
/// <summary>
/// DisposableBase class. Represents an implementation of the IDisposable interface.
/// </summary>
public abstract class DisposableBase : IDisposable
{
/// <summary>
/// A value which indicates the disposable state. 0 indicates undisposed, 1 indicates disposing
/// or disposed.
/// </summary>
private int disposableState;
/// <summary>
/// Finalizes an instance of the DisposableBase class.
/// </summary>
~DisposableBase()
{
// The destructor has been called as a result of finalization, indicating that the object
// was not disposed of using the Dispose() method. In this case, call the DisposeResources
// method with the disposeManagedResources flag set to false, indicating that derived classes
// may only release unmanaged resources.
this.DisposeResources(false);
}
/// <summary>
/// Gets a value indicating whether the object is undisposed.
/// </summary>
public bool IsUndisposed
{
get
{
return Thread.VolatileRead(ref this.disposableState) == 0;
}
}
#region IDisposable Members
/// <summary>
/// Performs application-defined tasks associated with disposing of resources.
/// </summary>
public void Dispose()
{
// Attempt to move the disposable state from 0 to 1. If successful, we can be assured that
// this thread is the first thread to do so, and can safely dispose of the object.
if (Interlocked.CompareExchange(ref this.disposableState, 1, 0) == 0)
{
// Call the DisposeResources method with the disposeManagedResources flag set to true, indicating
// that derived classes may release unmanaged resources and dispose of managed resources.
this.DisposeResources(true);
// Suppress finalization of this object (remove it from the finalization queue and
// prevent the destructor from being called).
GC.SuppressFinalize(this);
}
}
#endregion IDisposable Members
/// <summary>
/// Dispose resources. Override this method in derived classes. Unmanaged resources should always be released
/// when this method is called. Managed resources may only be disposed of if disposeManagedResources is true.
/// </summary>
/// <param name="disposeManagedResources">A value which indicates whether managed resources may be disposed of.</param>
protected abstract void DisposeResources(bool disposeManagedResources);
}
但是絕對和完整的整體是有爭議的評論了一下,無論在博客和這裏。
在完成之前,您不應該處置對象。如果有其他線程引用該對象,並且有可能需要調用它的方法,則不應該對其進行處理。
因此,Dispose不是必須的線程安全。
在一些情況下,優選的方式(如果不是唯一的方式)來強制一個阻塞I/O操作的放棄是'Dispose'從它的下面的連接的;例如可處置* *只從外螺紋發生(在阻塞的線程不能做任何事情,而它的阻止)。這是可能的外螺紋可能決定'Dispose'就像連接完成了其工作,並已被阻塞線程的連接決定'Dispose'它本身。 – supercat 2012-06-15 17:32:04
如果有一個用例另一個線程迫使阻塞操作的放棄,這需要有人來編寫代碼,使其工作。當然實施者將是明智的實現'ForceAbandon'方法拉澤而不是濫用'Dispose'的語義。如果實現者沒有意識到這是一個必需的用例,那麼你不能指望'Dispose'也能正確運行。它可能,但那只是運氣。 – Ben 2012-06-15 18:53:31
我見過很多I/O庫,其中唯一支持的跨線程操作正在終止連接。 「處置」似乎是最合適的。此外,在某些情況下,要保證局部構造的對象的清理最合理的方式可能涉及相互處置對方的對象,所以'Object1.Dispose'可以稱之爲'Object2.Dispose',這可能依次調用'Object1.Dispose '。防止這種情況不需要「互鎖」,但它仍然需要比微軟更好的模式。 – supercat 2012-06-15 19:42:33
線程安全的Dispose模式的唯一真正好處是您可以保證在發生跨線程誤操作時獲得ObjectDisposedException而不是潛在的不可預知的行爲。請注意,這意味着該模式需要超過線程安全的Dispose;它要求所有依賴不被處置的類的方法與處理機制正確地互鎖。
可以做到這一點,但是要覆蓋只有在存在使用錯誤(即錯誤)時纔會發生的邊界情況是很費事的。
我不確定Microsoft爲什麼不在非虛擬處置方法中使用互鎖Disposing標誌(打算終結器 - 如果有的話 - 應該使用相同的標誌)。多線程可能嘗試處理對象的情況很少,但並不禁止。例如,可能會發生這樣的對象,它們應該執行一些異步任務並自行清理,但如果需要,可以儘早將其清除。對象處理不應該經常發生,因爲Interlocked.Exchange有任何有意義的性能成本。
。另一方面,需要注意的是,同時保護對處置多次調用是一個恕我直言明智的政策是非常重要的,它是不足以使處置真的是線程安全的。還有必要確保在正在使用的對象上調用Dispose會使事情處於良好狀態。有時最好的模式是設置一個「KillMeNow」標誌,然後在由Monitor.TryEnter守護的塊中,處理該對象。它使用該對象必須既獲取之前和解除鎖定,以查看是否KillMeNow被設定後,即可獲得操作期間的鎖,但是測試每例程(比其它處置);如果是這樣,請執行Monitor.TryEnter並執行處理邏輯。
與進行線程安全的IDisposable更大的問題是,微軟並沒有指定一個事件的RemoveHandler方法必須是線程安全的了無死鎖的風險的事實。 IDisposable.Dispose經常需要刪除事件處理程序;如果沒有這種保證線程安全的方式,寫一個線程安全的Dispose幾乎是不可能的。
- 1. 爲什麼System.Net.Mail.MailMessage實現IDisposable
- 2. Enumerable.Range爲什麼實現IDisposable?
- 3. 爲什麼WCF RIA Services的DomainContext沒有實現IDisposable模式?
- 4. 爲什麼Stream類實現IDisposable?
- 5. 實現了IDisposable
- 6. 爲什麼我需要我需要在子類中實現IDisposable()
- 7. 實現IDisposable的C#
- 8. 爲什麼我得到協議Enumerable沒有爲#Ecto.Query實現?
- 9. 什麼時候和爲什麼沒有實現(java.lang.reflect.InvocationTargetException)發生?
- 10. CLR如何找到實現IDisposable的類?
- 11. 爲什麼JsArrayString沒有實現迭代?
- 12. 爲什麼LinkedHashMap沒有實現SortedMap?
- 13. 爲什麼AbstractAction沒有實現actionPerformed()?
- 14. 爲什麼ArrayList沒有實現隊列?
- 15. WhereSelectArrayIterator爲什麼沒有實現ICollection?
- 16. 爲什麼AbstractCollection沒有實現equals()?
- 17. 爲什麼java.util.TreeMap.KeySet沒有實現equals?
- 18. Android Ndk(沒有發現爲xxxxx實現)
- 19. 在父類還實現IDisposable時在子類上實現IDisposable
- 20. 爲什麼我得到「跨數據庫引用沒有實現」?
- 21. 爲什麼MongoDB C#驅動程序數據庫沒有實現IDisposable?
- 22. 實現IDisposable接口和拋出異常時會發生什麼
- 23. 爲什麼IDisposable的實現設計方式是
- 24. 爲什麼我的ObjC實現類#import實現協議的_interface_?
- 25. 爲什麼沒有發現這個謂詞的實例?
- 26. 爲什麼我的LLVM JIT實現會實現分段?
- 27. 爲什麼類會顯式而不是隱式地實現IDisposable?
- 28. 爲什麼析構函數不足以實現IDisposable?
- 29. 在API中實現IDisposable
- 30. System.Net.HttpListener只顯式實現IDisposable
@Hans:這不是根本錯誤;這是完全可能的,多線程希望在它們之間進行談判誰得到處置對象時,他們都與它在同一時間全部完成。 **談判協議必須由線程安全的部分組成。** Brian的博客不是「動盪」。 – 2011-03-14 14:55:11
這不是真正的線程安全的,因爲它沒有正確地解決其他方法調用該類的行爲必須如何。如果你真的想在Dispose上擁有線程安全性,最簡單的方法是將整個Dispose方法封裝在一個鎖中,並在每個公共方法周圍使用相同的鎖,並拋出ObjectDisposedException(如果已經處理)。如果您需要允許方法與Dispose方法並行執行,則可以使用MultiRead/SingleWrite模式,其中Dispose是「寫入」操作。 – 2011-03-14 14:56:21
@Eric:如果此協商正確實施,那麼它不需要IDisposable實現是線程安全的。談判需要。我沒有斷言Brian的博客是順便說一句。對不起,冒犯了你。 – 2011-03-14 14:59:35