【问题标题】:Trying to understand Microsoft's implementation of WeakReference试图了解微软对 WeakReference 的实现
【发布时间】:2011-12-29 19:16:09
【问题描述】:

作为一名试图习惯 .NET 的经验丰富的 C++ 程序员,Microsoft 的 WeakReference“Target”属性中有一个实现细节困扰着我......

public class WeakReference : ISerializable
{
    internal IntPtr m_handle;
    internal bool m_IsLongReference;
                 ...
    public virtual object Target
    {
        [SecuritySafeCritical]
        get
        {
            IntPtr handle = this.m_handle;
            if (IntPtr.Zero == handle)
            {
                return null;
            }
            object result = GCHandle.InternalGet(handle);
            if (!(this.m_handle == IntPtr.Zero))
            {
                return result;
            }
            return null;
        }
        [SecuritySafeCritical]
        set
        {
            IntPtr handle = this.m_handle;
            if (handle == IntPtr.Zero)
            {
                throw new InvalidOperationException(Environment.GetResourceString("InvalidOperation_HandleIsNotInitialized"));
            }
            object oldValue = GCHandle.InternalGet(handle);
            handle = this.m_handle;
            if (handle == IntPtr.Zero)
            {
                throw new InvalidOperationException(Environment.GetResourceString("InvalidOperation_HandleIsNotInitialized"));
            }
            GCHandle.InternalCompareExchange(handle, value, oldValue, false);
            GC.KeepAlive(this);
        }
    }
     ...
       }

困扰我的是——他们为什么要检查 m_handle 的有效性两次?特别是在“设置”方法中 - 在方法末尾使用 GC.KeepAlive 应该可以防止 WeakReference 被垃圾收集,从而保持句柄非零 - 对吗?

在“get”的情况下——一旦我们通过 InternalGet 实际检索到对目标的引用,为什么还要再次检查原始 m_handle 值?我所能想到的只是,也许他们试图防止在 InternalGet 期间或之后处理和完成 WeakReference - 但可以肯定的是,在我们返回对象之前,它不能也被处理和完成吗?我只是想不出一个有效的解释来解释为什么这里需要这种双重检查......

【问题讨论】:

  • 你为什么这么关心实现?您发布的是实际的 Microsoft 许可代码,还是 Mono 的?
  • +1 好问题。在这两个访问器中似乎没有多大意义。
  • @Dykam 阅读代码是一种很好的学习方式,将图书馆代码视为“魔法”是一种不学习和发展迷信的好方法。另外,我不想认为这个 sn-p 即使受版权保护也不属于合理使用范围。
  • @Complicatedseebio,这是真的,但我会有点犹豫自己发布 MS 代码。

标签: c# .net thread-safety weak-references


【解决方案1】:

我能想到的只是,也许他们正试图防范 WeakReference 在执行期间或之后被处理和完成 内部获取

完全正确。

但可以肯定的是,它不能也被处置和最终确定吗? 在我们开始返回对象之前?

不,因为此时,必须已创建指向该对象的强指针。 InternalGet 返回一个强指针,如果存储在 oldValue 中的强指针指向对象,那么现在垃圾收集器无法再回收该对象。

【讨论】:

  • InternalGet 的调用本身不会创建强指针,但无论它有什么实现。
  • @TomislavMarkovski 它确实有效,因为它正在为GCHandle(返回值)中引用的对象创建根。一旦你存储了返回值(oldValue),你就有了一个根 GC 引用,所以这个对象不再符合 GC 的条件。
  • 谢谢!仍然 - 我不太明白其中的逻辑。唯一可以将内部句柄归零的是终结器——因此,在此调用期间,句柄可以更改的唯一方法是在此过程中调用 Wea​​kReference 的终结器。假设我有一个对这个 WeakReference 的“僵尸”WeakReference ——所以我在这个 WeakReference 的终结器被安排之后调用“get”。仍然 - 对句柄进行第二次检查可以产生影响的唯一方法是,如果在第一次和第二次检查之间调用了 WR 的终结器。
  • 但是 - 在第二次检查和返回之间不能也调用终结器吗?我想我所看到的是任何依赖于第二次检查操作的东西仍然是一个竞争条件——即使是第二次检查......
  • @Kevin 我知道弱指针,但对 .NET 的细节知之甚少。不过,当您说“唯一可以将内部句柄归零的是终结器”时,我认为您倒退了。垃圾收集器将事物归零(并在适当时调用终结器)。并且垃圾收集器被设计为永远不会对存在实时强引用的对象执行此操作,oldValue 在您关注的事件序列中。
猜你喜欢
  • 2013-07-12
  • 1970-01-01
  • 1970-01-01
  • 2019-08-19
  • 2014-07-16
  • 2015-07-27
  • 2018-03-02
  • 2011-08-11
  • 2020-12-05
相关资源
最近更新 更多