简体   繁体   English

终结器和配置

[英]Finalizers and Dispose

I've got a class named BackgroundWorker that has a thread constantly running. 我有一个名为BackgroundWorker的类,它有一个不断运行的线程。 To turn this thread off, an instance variable named stop to needs to be true . 要关闭此线程,名为stop to的实例变量必须为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() . 为了确保在使用完类时释放线程,我添加了IDisposable和一个调用Dispose()的终结器。 Assuming that stop = true does indeed cause this thread to exit, is this sippet correct? 假设stop = true确实导致此线程退出,这个sippet是否正确? It's fine to invoke Dispose from a finalizer, right? 可以从终结器中调用Dispose ,对吗?

Finalizers should always call Dispose if the object inherits IDisposable , right? 如果object继承了IDisposable ,终结器应该总是调用Dispose ,对吧?

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

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

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. 现在回到原来的问题。

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

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. 如果你没有子类,那么密封你的班级并完全放弃终结器。

Out of interest, any reason this couldn't use the regular BackgroundWorker , which has full support for cancellation? 出于兴趣,任何原因都不能使用常规的BackgroundWorker ,它完全支持取消?

Re the lock - a volatile bool field might be less troublesome. 锁定 - 一个挥发性的bool领域可能不那么麻烦。

However, in this case your finalizer isn't doing anything interesting, especially given the "if(disposing)" - ie it only runs the interesting code during Dispose(). 但是,在这种情况下,你的终结器没有做任何有趣的事情,特别是考虑到“if(disposing)” - 即它只在Dispose()期间运行有趣的代码。 Personally I'd be tempted to stick with just IDisposable, and not provide a finalizer: you should be cleaning it up with Dispose(). 就个人而言,我很想坚持使用IDisposable,而不是提供终结器:你应该用Dispose()清理它。

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. 你的代码很好,虽然锁定终结器有点“可怕”而且我会避免它 - 如果你遇到了僵局......我不是100%肯定会发生什么但是它不会很好。 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. 正如Marc Gravell指出的那样,一个不稳定的布尔将允许你摆脱锁定,这将缓解这个问题。 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. nedruod的代码将赋值放在if(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. 是的,如果实现IDisposable模式,你几乎总是应该从终结器中调用Dispose()。 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: 完整的IDisposable模式比你有的大一点,但你并不总是需要它 - 它只提供了两个额外的可能性:

  1. detecting whether Dispose() was called or the finalizer is executing (you are not allowed to touch any managed resources in the finalizer, outside of the object being finalized); 检测Dispose()是否被调用或者终结器正在执行(不允许触摸终结器中的任何托管资源,在最终确定的对象之外);
  2. enabling subclasses to override the Dispose() method. 启用子类以覆盖Dispose()方法。

Is the "stop" instance variable a property? “stop”实例变量是属性吗? 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. 如果您实际上正在释放资源,那么让Dispose()和终结器执行相同的工作(首先测试是否仍需要完成工作)是一个很好的模式。

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. 考虑拥有一个线程所拥有的事件,并代之以发出信号。

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. 终结器应该使用类似于CompareExchange的东西来设置标志,并且线程应该使用类似的方法来测试它。 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. 如果你所做的只是设置一面旗帜,你就没事了。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM