gpt4 book ai didi

C# IDisposable、Dispose()、锁(this)

转载 作者:行者123 更新时间:2023-12-03 14:15:50 24 4
gpt4 key购买 nike

我是编程新手。我正在学习 John Sharp 的 Microsoft Visual C# Step by Step 9ed 的第 14 章。
我不明白一些点。

作者写道:

...它(终结器)可以在对对象的最后一个引用消失后随时运行。因此,当 Dispose 方法正在运行时,垃圾收集器实际上可能会在其自己的线程上调用终结器,尤其是在 Dispose 方法必须执行大量工作时。

1) 这里我有一个 第一个问题 , 这怎么可能?毕竟,当没有更多链接时,GC CLR 会正确地销毁该对象。但是,如果没有引用,那么如何仍然可以同时使用没有其他引用的对象(Dispose())的方法呢?是的,没有链接,但是方法没有完成,GC CLR 会尝试删除仍然有效的方法对象?

此外,作者建议使用 lock (this) 来规避这个问题(并行调用 Dispose ()),并通过立即提出本章前面描述的另一种策略来澄清这可能会损害性能。

class Example : IDisposable
{
private Resource scarce; // scarce resource to manage and dispose
private bool disposed = false; // flag to indicate whether the resource
// has already been disposed
...
~Example()
{
this.Dispose(false);
}

public virtual void Dispose()
{
this.Dispose(true);
GC.SuppressFinalize(this);
}

protected virtual void Dispose(bool disposing)
{
if (!this.disposed)
{
if (disposing)
{
// release large, managed resource here
...
}
// release unmanaged resources here
...
this.disposed = true;
}
}

//other methods
}

2) 我了解它的工作原理以及为什么需要它,但我无法准确提及 this.Dispose(true) 的并行执行。和 this.Dispose(false) .

在建议的最后一个解决方案中,这将不允许 GC CLR 调用 this.Dispose(false)方法在其线程中以与之前相同的方式通过析构函数并行执行 while this.Dispose(true)是否仍会在之前显式启动时执行?

乍一看,这是一个 GC.SuppressFinalize (this) 构造,但它应该只在 this.Dispose (true) 结束后工作,并且根据条件它执行的时间足够长,以便 GC CLR 在其线程中启动解构器和 this.Dispose(false) .

据我了解,没有什么可以阻止,我们只会重复丢弃非托管资源(文件、与数据库的连接等),但不会重复丢弃托管资源(例如,大型多维数组) .

事实证明,重复丢弃非托管资源是允许的,而重复丢弃托管资源是 Not Acceptable ?这比使用锁(this)构造更好吗?

最佳答案

1) Here I have a first question, how is this possible? After all, GC CLR destroys the object as correctly noticed when there are no more links to it. But if there are no references, how then can simultaneously still work the method of an object (Dispose()) to which nothing else refers? Yes, there are no links, but the method is not completed and GC CLR will try to delete the method object that still works?



想象一下,您有一个类似的方法:

void SomeMethod()
{
var unmanagedPtr = this.MyPointer;
while (/* some long loop */)
{
// lots of code that *just* uses unmanagedPtr
}
}

现在; this这里是 arg0 ,所以确实存在于堆栈中,但 GC允许查看何时读取本地值,并且 arg0没有读过前几条指令;所以从 GC的角度来看,可以忽略 arg0如果线程在 while环形。现在;想象一下,对这个对象的引用只存在于 arg0 中。 - 也许是因为它在堆栈上只是短暂的,即

new MyType(...).SomeMethod();

此时,是的,即使在其上执行方法,也可以收集该对象。在大多数情况下,我们不会注意到任何副作用,但是:终结器和非托管数据有点特殊,因为如果你的终结器使 unmanagedPtr 无效。该 while循环取决于:坏事。

此处最合适的修复方法可能是添加 GC.KeepAlive(this)SomeMethod结尾.重要的是,请注意 GC.KeepAlive 什么都不做 - 这是一种不透明、无操作、不可内联的方法,仅此而已。我们实际上通过添加 GC.KeepAlive(this)正在添加对 arg0 的读取,这意味着GC需要查看 arg0 ,所以它注意到该对象仍然可以访问,并且没有被收集。

2) Which in the proposed last solution will not allow GC CLR to call the this.Dispose(false) method in its thread in parallel through the destructor in the same way as before while this.Dispose(true) will still be executed previously launched explicitly?



让我们能够调用 Dispose() ,我们显然有一个引用,所以这很好。所以我们知道它至少在 Dispose 之前是可以访问的。 , 我们只讨论 Dispose(true)Dispose(false) 竞争.在这种情况下, GC.SuppressFinalize(this)有两个目的:
  • GC.SuppressFinalize(this) 的存在作用与 GC.KeepAlive 相同并将对象标记为可达;在达到该点之前无法收集它
  • 并且一旦达到,它根本不会最终确定
  • 关于C# IDisposable、Dispose()、锁(this),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60024288/

    24 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com