终结器和处理

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

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

如果objectinheritance了IDisposable ,终结器应该总是调用Dispose ,对吧?

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

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

正如Marc Gravell指出的那样,一个挥发性的bool会让你摆脱锁定,这将缓解这个问题。 如果可以的话,实施此更改。

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

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

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

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

 public void Dispose() { Dispose(true); GC.SuppressFinalize(this); } ///  /// Force the background thread to exit. ///  protected virtual void Dispose(bool disposing) { if (disposing) { lock (this.locker) { this.stop = true; } } } ~BackgroundWorker() { Dispose(false); } 

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

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

重新锁定 – 一个挥发性的bool领域可能不那么麻烦。

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

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

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

你需要完整的一次性模式,但停止必须是线程可以访问的东西。 如果它是要处理的类的成员变量,那就不好了,因为它不能引用已处理的类。 考虑有一个线程拥有的事件并发信号通知处置。

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