2008-09-29 18 views
4

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

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

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

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

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

错字在第一段? “假”应该是“真的”,对吗? – Blorgbeard 2008-09-29 22:39:35

回答

3

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

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

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

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

  1. 检测的Dispose()是否被调用或终结正在执行(你不能触摸终结器中的任何托管资源,在正在完成的对象之外);
  2. 使子类可以覆盖Dispose()方法。
0

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

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

+0

“stop”是一个私有变量。如果您不能从终结器中调用this.Dispose(),如何确保在GC清理对象时丢弃该对象? – core 2008-09-29 22:38:34

+0

我并不是说你不能调用Dispose - 我是说如果它只是一个变量就没有关系 - 对象正在消失。 – 2008-09-30 03:02:05

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

要不惜任何一个终结的唯一原因是为了让子类继承和释放非托管资源。如果你没有子类,那么密封你的班级,并完全放下终结者。

+3

重新发出“严重警告” - 由于“if(disposing)”检查,他*不会在终结器中锁定 - 仅在Dispose()中。也就是说,一个易变的布尔可能会更好。此代码仅在调用Dispose()时停止worker,这是合理且有效的用法。 – 2008-09-30 06:55:46

3

出于兴趣,任何原因,这可能无法使用正常的BackgroundWorker,它完全支持取消?

重新锁定 - 一个易变的布尔字段可能不太麻烦。

但是,在这种情况下,您的终结器没有做任何有趣的事情,尤其是给予“if(disposing)” - 即它只在Dispose()期间运行有趣的代码。就我个人而言,我试图坚持使用IDisposable,而不是提供终结器:您应该使用Dispose()进行清理。

0

实现终结的对象需要一个标志的参考 - 存储在另一个对象,可呈现线程将能够看到;线程必须而不是对实现终结器的对象有直接或间接的强引用。终结器应该使用像CompareExchange这样的东西来设置标志,并且该线程应该使用类似的方法来测试它。请注意,如果一个对象的终结器访问另一个对象,另一个对象可能已经完成,但它仍然存在。对于终结器来说,引用其他对象是没有问题的,如果这样做不会被终结者所困扰。如果你所做的只是设置一个标志,那你就很好。