终结器和配置

时间:2008-09-29 22:28:27

标签: c# dispose idisposable finalizer disposable

我有一个名为BackgroundWorker的类,它有一个不断运行的线程。要关闭此线程,名为stop的实例变量需要为true

为了确保在使用完课程后释放线程,我添加了IDisposable和一个调用Dispose()的终结器。假设stop = true确实导致此线程退出,这个sippet是否正确?可以从终结器中调用Dispose,对吧?

如果Dispose继承object,那么终结者应始终致电IDisposable,对吗?

/// <summary>
/// Force the background thread to exit.
/// </summary>
public void Dispose()
{
    lock (this.locker)
    {
        this.stop = true;
    }
}

~BackgroundWorker()
{
    this.Dispose();
}

6 个答案:

答案 0 :(得分:11)

首先,严重警告。不要像你一样使用终结器。如果你在终结器中取得锁定,你就会为自己设置一些非常糟糕的效果。短篇小说是不要做的。现在回到原来的问题。

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

/// <summary>
/// Force the background thread to exit.
/// </summary>
protected virtual void Dispose(bool disposing)
{
    if (disposing)
    {
        lock (this.locker)
        {
            this.stop = true;
        }
    }
}

~BackgroundWorker()
{
    Dispose(false);
}

拥有终结器的唯一原因是允许子类扩展和释放非托管资源。如果你没有子类,那么密封你的班级并完全放弃终结器。

答案 1 :(得分:3)

出于兴趣,任何原因都不能使用常规BackgroundWorker,它完全支持取消?

重新锁定 - 一个挥发性的bool字段可能不那么麻烦。

然而,在这种情况下,你的终结器没有做任何有趣的事情,特别是考虑到“if(disposing)” - 即它只在Dispose()期间运行有趣的代码。就个人而言,我很想坚持使用IDisposable,而不是提供终结器:你应该用Dispose()清理它。

答案 2 :(得分:3)

你的代码很好,虽然锁定终结器有点“可怕”,我会避免它 - 如果你遇到僵局......我不是100%肯定会发生什么,但这不会是好事。但是,如果你是安全的,这应该不是问题。大多。垃圾收集的内部是痛苦的,我希望你永远不必看到它们;)

正如Marc Gravell指出的那样,一个挥发性的布尔将允许你摆脱锁定,这将缓解这个问题。如果可以,请实施此更改。

nedruod的代码将赋值放在if(disposing)检查中,这是完全错误的 - 该线程是一个非托管资源,即使没有明确处理也必须停止。您的代码很好,我只是指出您不应该接受该代码段中给出的建议。

是的,如果实现IDisposable模式,你几乎总是应该从终结器中调用Dispose()。完整的IDisposable模式比你有的大一点,但你并不总是需要它 - 它只提供了两个额外的可能性:

  1. 检测是否已调用Dispose()或正在执行终结器(在最终确定的对象之外,不允许触摸终结器中的任何托管资源);
  2. 启用子类以覆盖Dispose()方法。

答案 3 :(得分:0)

“stop”实例变量是属性吗?如果没有,在终结器中设置它没有特别的意义 - 没有任何东西可以引用该对象,所以没有任何东西可以查询该成员。

如果您实际上正在释放资源,那么让Dispose()和终结器执行相同的工作(首先测试是否仍需要完成工作)是一个很好的模式。

答案 4 :(得分:0)

您需要完整的一次性模式,但停止必须是线程可以访问的内容。如果它是要处理的类的成员变量,那就没有用,因为它不能引用已处理的类。考虑拥有该线程拥有的事件并发信号通知该部署。

答案 5 :(得分:0)

实现终结器的对象需要引用一个标志 - 存储在另一个对象中的 - 线程将能够看到;线程必须对实现终结器的对象有任何直接或间接的强引用。终结器应该使用类似于CompareExchange的东西来设置标志,并且线程应该使用类似的方法来测试它。请注意,如果一个对象的终结器访问另一个对象,则另一个对象可能已经完成,但它仍然存在。终结者可以引用其他对象,如果它以一种不会被其最终确定所困扰的方式这样做。如果你正在做的只是设置一个标志,你就没事了。