2011-02-17 82 views
8

MSDN很好地記錄了BCL類型的實例成員的線程安全性,但是我從未真正看到過指示類型的方法如何被調用的信息。線程安全的Dispose方法?

Dispose方法a)保證對所有類都是線程安全的,b)從來不保證是線程安全的,c)保證對於某些類是線程安全的(如果是這樣, )?

最後,如果Dispose方法保證是線程安全的,那麼這是否意味着我必須鎖定使用一次性資源的類中的每個實例方法?我知道類型的終結器應該是線程安全的,因爲垃圾回收在.NET中的工作方式(相當積極),他們可能會調用Dispose方法。不過,讓我們把這個問題放在這裏。

+0

也許這可以幫助:http://stackoverflow.com/questions/151000/finalizers-and-dispose。 – 2011-02-17 04:05:39

+0

謝謝,但那不是我所問的。此外,我並不在乎這裏的終結者。 – Noldorin 2011-02-17 04:07:01

+0

重新說明你的觀點,你不應該明確調用`Dispose`並且不要依賴Finalizer線程來做到這一點嗎? – 2011-02-17 04:07:39

回答

6

線程安全和Dispose的問題有點棘手。由於在許多情況下,任何線程可能合法地對一個對象做任何其他線程開始處理它的唯一的事情就是試圖自己處理它,它首先會腮紅似乎是確保線程安全的唯一必要條件。在'dispose'標誌上使用Interlocked.Exchange來確保一個線程的Dispose嘗試發生,而另一個線程被靜默地忽略。事實上,這是一個很好的起點,我認爲它應該是標準Dispose模式的一部分(CompareExchange應該在密封的基類包裝方法中完成,以避免每個派生類需要使用它自己的私有處置標誌)。不幸的是,如果考慮Dispose的實際情況,事情就會複雜得多。

Dispose的真正目的不是對被處理的對象做些什麼,而是清理該對象持有引用的其他實體。這些實體可能是管理對象,系統對象或其他東西;他們甚至可能不在與處理對象相同的計算機上。爲了讓Dispose成爲線程安全的,其他實體將允許Dispose在與其他線程可能正在做其他事情的同時清理它們。有些物體可以處理這種用法;別人不能。

一個特別令人煩惱的例子:允許對象具有非線程安全的RemoveHandler方法的事件。因此,任何清理事件處理程序的Dispose方法都只能從創建訂閱的同一線程調用。

2

MSDN here上的頁面從來沒有真正明確指出Dispose方法不是線程安全的,但對我的閱讀而言,它們的代碼暗示着不,它們不是線程安全的,如果需要,您需要說明。

具體地,在該示例代碼中的註釋:

// This class shows how to use a disposable resource. 
// The resource is first initialized and passed to 
// the constructor, but it could also be 
// initialized in the constructor. 
// The lifetime of the resource does not 
// exceed the lifetime of this instance. 
// This type does not need a finalizer because it does not 
// directly create a native resource like a file handle 
// or memory in the unmanaged heap. 

public class DisposableResource : IDisposable 
{ 

    private Stream _resource; 
    private bool _disposed; 

    // The stream passed to the constructor 
    // must be readable and not null. 
    public DisposableResource(Stream stream) 
    { 
     if (stream == null) 
      throw new ArgumentNullException("Stream in null."); 
     if (!stream.CanRead) 
      throw new ArgumentException("Stream must be readable."); 

     _resource = stream; 

     _disposed = false; 
    } 

    // Demonstrates using the resource. 
    // It must not be already disposed. 
    public void DoSomethingWithResource() { 
     if (_disposed) 
      throw new ObjectDisposedException("Resource was disposed."); 

     // Show the number of bytes. 
     int numBytes = (int) _resource.Length; 
     Console.WriteLine("Number of bytes: {0}", numBytes.ToString()); 
    } 


    public void Dispose() 
    { 
     Dispose(true); 

     // Use SupressFinalize in case a subclass 
     // of this type implements a finalizer. 
     GC.SuppressFinalize(this);  
    } 

    protected virtual void Dispose(bool disposing) 
    { 
     // If you need thread safety, use a lock around these 
     // operations, as well as in your methods that use the resource. 
     if (!_disposed) 
     { 
      if (disposing) { 
       if (_resource != null) 
        _resource.Dispose(); 
        Console.WriteLine("Object disposed."); 
      } 

      // Indicate that the instance has been disposed. 
      _resource = null; 
      _disposed = true; 
     } 
    } 
} 
2

我相當肯定的是,除非另有說明,任何類別的Dispose()方法將計爲用於文檔的目的指示線程安全的「實例成員」或不。

因此,如果文檔指出實例成員不是線程安全的,那麼Dispose()也不一定是,除非特別指出它與其餘部分不同。