2014-10-30 73 views
3

以下是有关这我不清楚一个例子:如何正确处理来自终结器的非托管资源的收集?

public class SomeClass : IDisposable { 

    ~SomeClass() { 
     Dispose(false); 
    } 

    public void Dispose() { 
     Dispose(true); 
     GC.SuppressFinalize(this); 
    } 

    private bool _disposed; 

    protected virtual void Dispose(bool disposing) { 
     if (!_disposed) { 
      if (disposing) { 
       // TODO: Release any managed resources here... 
      } 

      // ?! Is it safe to enumerate the dictionary here ?! 
      foreach (var resource in _resources.Values) 
       ReleaseBuffer(resource); 
      _resources = null; 

      _disposed = true; 
     } 
    } 

    private Dictionary<string, IntPtr> _resources; 

    ... 

} 

会不会是安全的枚举管理字典,以释放非托管资源?

由于未定义终结器的顺序,因此字典的可用性是否不确定?

这里是从MSDN截取的报价,我感到迷惑[1]:即使一个对象指的是

  • 两个对象的终结不能保证在任何特定的顺序运行,其他。也就是说,如果对象A具有对象B的引用并且都具有终结器,则在对象A的终结器开始时,对象B可能已经完成。
  1. http://msdn.microsoft.com/en-us/library/system.object.finalize(v=vs.110).aspx
+1

它应该是安全的,字典是一个管理对象,根植于您的类的实例,它将被访问,直到调用终结器。请参阅http://stackoverflow.com/questions/13954829/gc-collect-and-finalize。 – galenus 2014-10-30 19:42:24

+2

'Dictionary'没有终结符。所以你很安全。 – Blorgbeard 2014-10-30 19:43:41

+2

@Blorgbeard:字典不是线程安全的,对于运行终结器的线程上下文没有任何保证。 – supercat 2014-10-31 20:24:27

回答

2

而不是有一个非托管资源字典,我会建议有一个独立的包装对象的字典,其中每个负责保护一个非托管资源。如果持有该字典的对象被放弃并且包装对象不存在其他引用,则所有包装对象都将被终止,而不需要在该过程中涉及字典本身。使用这种方法可以更容易地处理在对象构建过程中发生异常的情况,并且至少在某种程度上理解了一个对象发现自己在被终止排队的时间和终结器的时间之间复活的情况运行[在这种情况下,代码一般不能期望“正确运行”,但应避免破坏系统其余部分的状态]。例如,使用句柄的代码在使用过程中可能会获取锁,并且在使用后检查“disposeObjectASAP”标志;如果设置,重新获得锁和处置对象。终结器本身应该设置标志,然后尝试获取锁定;如果它成功获得锁定,则应该处理该对象。如果不行,它设置标志的事实应该暗示有锁的代码注定要检查标志并清理对象,所以终结器不必。如果终结器过早运行,它可能释放另一个线程将需要的资源,导致该另一个线程上的操作失败,但终结器不会释放资源,而另一个线程正在使用它们或处置它们,因为释放那些资源情况可能导致大规模的系统损坏

0

Implementing a Dispose method,你看那里是不是安全的代码。

的代码示例显示:

protected virtual void Dispose(bool disposing) 
{ 
    if (disposed) 
     return; 

    if (disposing) { 
     // Free any other managed objects here. 
     // 
    } 

    // Free any unmanaged objects here. 
    // 
    disposed = true; 
} 

你的样品显示您在条件块释放非托管资源。 MSDN示例显示您应该在条件块中释放管理的资源。

,因为它说的文本(标题“的Dispose(布尔)过载”下):

如果方法调用来自一个终结(即,如果处置是false),只释放非托管资源的代码将执行。由于未定义垃圾收集器在最终化​​过程中销毁托管对象的顺序,因此调用Dispose重载的值为false可防止终结器尝试释放可能已被收回的托管资源。

+0

我的'if(disposing)'语句里的注释完全是一个错字。但是打算访问'_resources'集合。为了将来的清晰度,我已经在我的问题中纠正了这个错字。谢谢 – 2014-10-30 21:36:13