带析构函数的 IDisposable:需要线程安全实现?

发布于 2024-10-12 12:09:36 字数 460 浏览 3 评论 0原文

这几乎只是我需要确保的,我做对了:

我们有一个实现 IDisposal 模式的大型资源类。它应该(根据设计)以一种使其能够被多次调用的方式实现(当然,即使我们尝试精确地调用它一次)。我们还实现了一个终结器,它也调用 Dispose() 方法 - 只是作为备份。如果手动调用,Dispose() 也会调用 GC.SuppressFinalize(this)。

周围有几个处置模式的例子。他们中的大多数在处理代码的末尾调用GC.SuppressFinalize(this)。有些人声称,最好在 Dispose() 方法的开头、任何清理之前调用它。后者认为,这将确保 GC 在我们仍在清理时不会同时调用终结器。

问题:
看来,将 GC.SuppressFinalize 放在开头并没有更好的效果?我们仍然有竞争条件,对吧?那么,我们是否应该以线程安全的方式实现 Dispose() 呢?

This is pretty much only for me to make sure, I got this right:

We have a large resource class implementing the IDisposal pattern. It should (by design) be implemented in a way, that enables it to get called more than one time (even if we try to call it exactly one time of course). We also implement a finalizer, which also calls the Dispose() method - just as backup. If called manually, Dispose() will also call GC.SuppressFinalize(this).

There are several examples of disposal patterns around. Most of them call GC.SuppressFinalize(this) at the end of the disposing code. Some claim, it would be better, to call it at the beginning of the Dispose() method, before any cleaning. Latter argue, this would make sure, the GC doesn't call the finalizer concurrently, while we are still cleaning up.

Question:
It seems, placing GC.SuppressFinalize at the beginning doesn't do any better? We still have a race condition, right? So is it true, that we rather should implement Dispose() in a thread safe way instead?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

困倦 2024-10-19 12:09:36

GC 仅清理不可“访问”的对象。

正在执行代码的类仍然是“可访问的”,因为它的 this 指针位于堆栈上。因此,当执行 dispose 时,不会调用终结器。

因此,无论您在开始还是结束时调用 SuppressFinalize 都没有关系。

正如下面的评论者指出的,CLR 实现似乎不能保证< /strong> 在执行实例方法时,您的对象不会被垃圾收集/最终确定。使对象保持活动状态的唯一可能的“可靠”引用是用于调用对象上的方法的引用,但我对 JIT 内部结构了解不够,无法对此做出声明,并且它的行为可能会改变。

我将答案留在这里以便访问下面的讨论。

The GC only cleans up objects that are not 'reachable'.

A class in which code is executing is still 'reachable' because it's this pointer is on the stack. So while dispose is executing, the finalizer won't be called.

So it does not matter if you call SuppressFinalize at the begin or end.

As commentors below indicated, the CLR implementation does not appear to guarantee that your object does not get garbage collected/finalized while instance methods are executing. The only possible 'dependable' reference keeping the object alive is the one used to invoke the method on the object, but I don't know enough about the JIT internals to make statements about that, and it's behaviour might change.

I'm leaving the answer here for access to the discussion below.

时光无声 2024-10-19 12:09:36

虽然有时在存在看似活跃的引用时对象可能会被最终确定,但这只有在没有其他东西引用该对象时才会发生。 GC.SuppressFinalize(this) 主动引用当前对象“this”,从而保证在 GC.SuppressFinalize 执行之前它不会被最终确定。此外,对象引用的存在是为了处置该对象,并且可供 Dispose 方法使用,这一事实保证了在 Dispose 开始运行之前终结器不会排队,除非该对象已死亡并且某处有终结器(无论是它自己的终结器) ,或其他一些物体)复活了它。

因为在某些情况下,对象可能会在不知情的情况下被安排进行终结和复活,因此保护处置和终结以防止冗余操作可能不是一个坏主意。然而,微软的模式并不好。可终结的对象不应保留对终结不需要的任何对象的引用。如果一个对象包含托管和非托管资源的混合体,则应将非托管资源移至它们自己的类中(有效地将它们转变为托管资源),这样主对象将只包含托管资源。

While it is sometimes possible for an object to be finalized while a seemingly-live reference exists, that can only happen when nothing else is going to ever refer to the object. The GC.SuppressFinalize(this) actively refers to the present object 'this', thus guaranteeing that it will not be finalized until the GC.SuppressFinalize executes. Further, the fact that the object reference existed to dispose the object, and was available to the Dispose method, guarantees that the finalizer couldn't have been queued before Dispose started running unless the object was dead and a finalizer somewhere (either its own finalizer, or that of some other object) resurrected it.

Because there are some scenarios where an object could be scheduled for finalization and resurrected without ever being aware of it, it may not be a bad idea to protect a dispose and finalize against redundant operation. Microsoft's pattern is not a good one, however. Finalizable objects shouldn't hold references to any objects not needed for finalization. If an object would hold a mixture of managed and unmanaged resources, the unmanaged resources should be moved into their own classes (effectively turning them into managed resources), so then the main object would hold nothing but managed resources.

℉服软 2024-10-19 12:09:36

Dispose 不应引发任何异常。

我会确保 Dispose 中的所有代码都是线程安全的,这样如果它被调用,它就不会做任何奇怪的事情。通常添加检查变量是否已经为空应该可以解决问题。

在微软的示例中,我只在 Dispose 函数末尾看到 GC.SuppressFinalize 。

Dispose should not throw any exceptions.

I would make sure all the code in Dispose is thread safe so that if it gets called it will not do anything strange. Usually adding checks if variables are null already should do the trick.

In the microsoft examples i've only seen GC.SuppressFinalize at the end of the Dispose function.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文