终结器和处置
我有一个名为 BackgroundWorker
的类,它有一个不断运行的线程。 要关闭此线程,名为 stop
的实例变量需要为 true
。
为了确保在类使用完毕后释放线程,我添加了 IDisposable
和一个调用 Dispose()
的终结器。 假设 stop = true 确实导致该线程退出,这个 sippet 正确吗? 从终结器调用 Dispose 没问题,对吧?
如果对象
继承IDisposable
,终结器应该始终调用Dispose
,对吧?
/// <summary>
/// Force the background thread to exit.
/// </summary>
public void Dispose()
{
lock (this.locker)
{
this.stop = true;
}
}
~BackgroundWorker()
{
this.Dispose();
}
I've got a class named BackgroundWorker
that has a thread constantly running. To turn this thread off, an instance variable named stop
to needs to be true
.
To make sure the thread is freed when the class is done being used, I've added IDisposable
and a finalizer that invokes Dispose()
. Assuming that stop = true
does indeed cause this thread to exit, is this sippet correct? It's fine to invoke Dispose
from a finalizer, right?
Finalizers should always call Dispose
if the object
inherits IDisposable
, right?
/// <summary>
/// Force the background thread to exit.
/// </summary>
public void Dispose()
{
lock (this.locker)
{
this.stop = true;
}
}
~BackgroundWorker()
{
this.Dispose();
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(6)
首先,严重警告。 不要像你一样使用终结器。 如果你在终结器中进行锁定,你就会给自己带来一些非常糟糕的影响。 简而言之就是不要这样做。 现在回到原来的问题。
拥有终结器的唯一原因是允许子类扩展和释放非托管资源。 如果您没有子类,则密封您的类并完全删除终结器。
First off, a severe warning. Don't use a finalizer like you are. You are setting yourself up for some very bad effects if you take locks within a finalizer. Short story is don't do it. Now to the original question.
The only reason to have a finalizer at all is to allow sub-classes to extend and release unmanaged resources. If you don't have subclasses then seal your class and drop the finalizer completely.
出于兴趣,任何原因都无法使用常规 BackgroundWorker ,哪个完全支持取消?
重新锁定 - 易失性布尔字段可能不那么麻烦。
然而,在这种情况下,你的终结器没有做任何有趣的事情,特别是考虑到“if(dispose)”——即它只在 Dispose() 期间运行有趣的代码。 就我个人而言,我倾向于只使用 IDisposable,而不提供终结器:您应该使用 Dispose() 清理它。
Out of interest, any reason this couldn't use the regular BackgroundWorker, which has full support for cancellation?
Re the lock - a volatile bool field might be less troublesome.
However, in this case your finalizer isn't doing anything interesting, especially given the "if(disposing)" - i.e. it only runs the interesting code during Dispose(). Personally I'd be tempted to stick with just IDisposable, and not provide a finalizer: you should be cleaning it up with Dispose().
你的代码很好,虽然锁定终结器有点“可怕”,我会避免它 - 如果你遇到死锁......我不能 100% 确定会发生什么,但这不会很好。 但是,如果您安全的话,这应该不是问题。 大多。 垃圾收集的内部结构是痛苦的,我希望你永远不必看到它们;)
正如 Marc Gravell 指出的那样,易失性布尔将允许你摆脱锁,这将缓解这个问题。 如果可以的话,实施此更改。
nedruod 的代码将赋值放在 if(处置)检查中,这是完全错误的 - 线程是非托管资源,即使没有显式处置也必须停止。 您的代码很好,我只是指出您不应该接受该代码片段中给出的建议。
是的,如果实现 IDisposable 模式,您几乎总是应该从终结器调用 Dispose()。 完整的 IDisposable 模式比您所拥有的要大一些,但您并不总是需要它 - 它仅提供两种额外的可能性:
Your code is fine, although locking in a finalizer is somewhat "scary" and I would avoid it - if you get a deadlock... I am not 100% certain what would happen but it would not be good. However, if you are safe this should not be a problem. Mostly. The internals of garbage collection are painful and I hope you never have to see them ;)
As Marc Gravell points out, a volatile bool would allow you to get rid of the lock, which would mitigate this issue. Implement this change if you can.
nedruod's code puts the assignment inside the if (disposing) check, which is completely wrong - the thread is an unmanaged resource and must be stopped even if not explicitly disposing. Your code is fine, I am just pointing out that you should not take the advice given in that code snippet.
Yes, you almost always should call Dispose() from the finalizer if implementing the IDisposable pattern. The full IDisposable pattern is a bit bigger than what you have but you do not always need it - it merely provides two extra possibilities:
“stop”实例变量是属性吗? 如果不是,则在终结器期间设置它没有什么特别的意义 - 没有任何东西再引用该对象,因此没有任何东西可以查询该成员。
如果您实际上要释放资源,那么让 Dispose() 和终结器执行相同的工作(首先测试该工作是否仍然需要完成)是一个很好的模式。
Is the "stop" instance variable a property? If not, there's no particular point in setting it during the finalizer - nothing is referencing the object anymore, so nothing can query the member.
If you're actually releasing a resource, then having Dispose() and the finalizer perform the same work (first testing whether the work still needs to be done) is a good pattern.
您需要完整的一次性图案,但停止点必须是线程可以访问的地方。 如果它是被释放的类的成员变量,那就不好了,因为它不能引用已释放的类。 考虑让线程拥有一个事件并在处理时发出信号。
You need the full disposable pattern but the stop has to be something the thread can access. If it is a member variable of the class being disposed, that's no good because it can't reference a disposed class. Consider having an event that the thread owns and signaling that on dispose instead.
实现终结器的对象需要对存储在另一个对象中的标志的引用,线程将能够看到该标志; 线程不得对实现终结器的对象有任何直接或间接的强引用。 终结器应该使用类似 CompareExchange 的东西设置标志,并且线程应该使用类似的方法来测试它。 请注意,如果一个对象的终结器访问另一个对象,则另一个对象可能已被终结,但它仍然存在。 终结器可以引用其他对象,只要它的引用方式不会受到其终结的影响。 如果您所做的只是设置一个标志,那就没问题。
The object that implements the finalizer needs a reference to a flag--stored in another object--which the thread will be able to see; the thread must not have any strong reference, direct or indirect, to the object that implements the finalizer. The finalizer should set the flag using something like a CompareExchange, and the thread should use a similar means to test it. Note that if the finalizer of one object accesses another object, the other object may have been finalized but it will still exist. It's fine for a finalizer to reference other objects if it does so in a way that won't be bothered by their finalization. If all you're doing is setting a flag, you're fine.