2011-02-17 84 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()也不一定是,除非特别指出它与其余部分不同。