为什么在这里使用Thread.MemoryBarrier?

Mar*_*cic 6 c# thread-safety

浏览MEF源代码我发现了这篇文章.有人可以解释为什么MemoryBarrier需要锁定?

整个方法是:

public void SatisfyImportsOnce(ComposablePart part)
{
    this.ThrowIfDisposed();

    if (this._importEngine == null)
    {
        ImportEngine importEngine = new ImportEngine(this, this._compositionOptions);

        lock(this._lock)
        {
            if (this._importEngine == null)
            {
                Thread.MemoryBarrier();
                this._importEngine = importEngine;
                importEngine = null;
            }
        }
        if(importEngine != null)
        {
            importEngine.Dispose();
        }
    }
    this._importEngine.SatisfyImportsOnce(part);
}
Run Code Online (Sandbox Code Playgroud)

Vla*_*den 1

Thread.MemoryBarrier可防止抖动/编译器为代码优化而重新排序任何指令。

Joe Albahari 所著的《Treading in C#》一书中,他说道:

  • 编译器、CLR 或 CPU 可能会重新排序程序的指令以提高效率。
  • 编译器、CLR 或 CPU 可能会引入缓存优化,以便其他线程不会立即看到变量的分配。

在此示例中,可能会缓存 importEngine 或 _importEngine 值,并且必须立即通知所有线程有关更改,这一点非常重要。

在这种情况下,MemoryBarrier 在分配给 _importEngine 之前还提供 importEngine新鲜度保证

  • 在 CLI(CLR 的标准化版本)中,对双重检查锁定惯用法的基本空检查是不够的。CLI 的内存模型要求变量是易失性的,或者使用显式屏障。CLR具有更强的内存模型,并且不需要易失性和屏障。该代码的作者可能没有意识到 CLR 的额外保证,或者像 Jon Skeet 一样不喜欢依赖它们。屏障的成本有限,因为一旦初始化和同步,以后的调用将完全跳过锁的内容。 (2认同)