其他分享
首页 > 其他分享> > 如何正确处置来自终结器的非托管资源集合?

如何正确处置来自终结器的非托管资源集合?

作者:互联网

这是一个我不确定的示例:

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]:

  • The finalizers of two objects are not guaranteed to run in any specific order, even if one object refers to the other. That is, if Object A has a reference to Object B and both have finalizers, Object B might have already been finalized when the finalizer of Object A starts.

> http://msdn.microsoft.com/en-us/library/system.object.finalize(v=vs.110).aspx

解决方法:

我建议不要拥有一个独立的包装对象字典,而不是拥有一个非托管资源字典,每个包装对象负责保护一个非托管资源.如果放弃了保存字典的对象,并且包装器对象不存在其他引用,则所有包装器对象都将被最终确定,而无需在过程中涉及字典本身.使用这种方法将更容易合理地处理在对象构造期间发生异常的情况,并且至少在某种程度上合理地处理了在将对象排队到终结后和终结器之间发现自己已复活的情况.运行[在这种情况下,通常不能期望代码“正确”运行,但应避免破坏系统其余部分的状态].

例如,使用句柄的代码可能会在其使用过程中获取锁,并在使用后检查“ disposeObjectASAP”标志;如果已设置,请重新获取锁并处理对象.终结器本身应设置标志,然后尝试获取锁;如果成功获取了锁,则应该处置该对象.如果无法设置标志,则它设置标志的事实应表明具有锁定的代码将注定要检查标志并清理对象,因此终结器不必这样做.如果终结器过早运行,则它可能释放另一个线程将需要的资源,从而导致该另一个线程上的操作失败,但是终结器不会在另一个线程正在使用或处置它们时释放资源,因为在那些线程中释放资源情况可能会导致大规模系统损坏.

标签:collections,idisposable,dispose,c,net
来源: https://codeday.me/bug/20191121/2049214.html