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

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

如果 object 继承 IDisposable ,终结者应该总是调用 Dispose ,对吗?

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

~BackgroundWorker()
{
    this.Dispose();
}
有帮助吗?

解决方案

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

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

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

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

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

其他提示

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

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);
}

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

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

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

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

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

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

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

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

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top