2015-09-28 85 views
6

瀏覽MEF源代碼我找到了這一塊。 有人可以解釋爲什麼在鎖內需要MemoryBarrier爲什麼在這裏使用Thread.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); 
} 
+0

之前就*似乎*有時候,鎖不夠 –

+0

這是不可能回答這個問題,不知道多了很多內容。 –

+3

這是微軟內存模式的處理器上的FUD,一些微軟程序員可能永遠不會從馴服安騰處理器中恢復過來。它確保另一個線程在使用_importEngine引用時可以觀察完全構造的對象。在弱處理器上,在寫入對象字段之前可以將引用寫入內存,以便另一個線程可以看到未初始化的字段值。因爲.NET 2.0並不是必需的,並且在這裏絕對沒有必要,因爲鎖已經意味着內存屏障。 –

回答

1

Thread.MemoryBarrier防止抖動/編譯器的任何指令重新排序代碼優化。

Treading in C#, by Joe Albahari本書中,他最高審計機關:

  • 編譯器,CLR,或CPU可能會重新排列你的程序的指令來提高效率。
  • 編譯器,CLR或CPU可能會引入緩存優化,以便對其他線程立即無法看到變量賦值。

在這個例子中,可能會導致importEngine或_importEngine值被緩存,所有線程都必須立即通知所有線程。

在這種情況下內存屏障提供importEngine 新鮮 garantee它分配給_importEngine

+1

但鎖也意味着一個內存barrior。 'importEngine'和'_importEngine'都不能在鎖內緩存。 (除非其他東西在不鎖定this._lock的情況下寫入'_importEngine')。 –

+0

@ScottChamberlain你是對的。這就是爲什麼我認爲在這種情況下使用MemoryBarrier的原因,可能有其他線程在不使用_lock的情況下寫入_importEnginge。 –

+2

在CLI(CLR的標準化版本)中,對雙重檢查的鎖定語言的基本空檢查功能不足。 CLI的內存模型需要變量是易變的,或者使用明確的障礙。 CLR具有更強大的內存模型,既不需要波動也不需要屏障。該代碼的作者可能沒有意識到CLR的額外保證,或者Jon Skeet更喜歡不依賴它們。障礙成本有限,因爲一旦初始化和同步,以後的調用將完全跳過鎖的內容。 –

相關問題