2012-07-16 48 views
0

我知道這個話題已經被打砸了,因爲我已經閱讀了SO和其他地方的帖子的帖子,但我還沒有找到一個明確的答案,所以我道歉,如果你是被這種看似冗餘的感覺所感染。一次寫多次鎖

我有一種情況,有一次寫入,讀取百萬資源。該資源的創建非常昂貴,並且寫入鎖的爭用也可能非常高。此外,我無法預測它將運行在哪個處理器上,所以我不知道內存模型將在下面。我正在編譯.NET 3.5,.NET 4.0和Mono 2.10中構建的程序集的3個版本。

由於對資源的高度爭用,我需要儘可能提高效率,並且希望至少在讀取時使用無鎖模式。我理解用於創建資源的雙重鎖定檢查模式,但是由於_resource訪問內存障礙之外,它是否工作(在所有處理器上)存在分歧。我需要在_resource字段上使用volatile嗎? ReaderWriterLockSlim更適合這種情況嗎?我應該問什麼其他問題?

if(_resource == null) 
{ 
    lock(_locker) 
    { 
     if(_resource == null) 
     { 
      //create resource here... 
     }  
    } 
} 

此外,還會有許多這樣的:

if(_resource == null) 
{ 
    return _resourceDefault; 
} 

return _resource.GetSomething(); 
+0

爲什麼還要在這裏鎖定? – leppie 2012-07-16 12:11:59

+0

由於創建資源非常昂貴,我不能讓它多做一次。它包括跟蹤連接的服務器的遠程通信。 – 2012-07-16 12:41:17

+0

好吧,早在線程開始閱讀之前就已經完成了。不需要鎖。這一切都太模糊,不能給出具體的建議。 – 2012-07-16 13:58:58

回答

1

決定推動我一個答案評論。

在創建單例讀取時,http://msdn.microsoft.com/en-us/library/ff650316.aspx。它交叉鏈接一篇文章,深入解釋與雙重檢查鎖定有關的一些問題。爲了完全安全,微軟的文章推薦使用volatile。

如果你真的只想創建一個singleton(一次性事物...沒有鎖定促銷或任何必要的東西,你真的只需要保護創建資源)。一旦創建資源,您將不會觸摸該鎖。

我會設計訪問你的單例總是經歷一個靜態屬性/方法,所以你可以隨時做雙重檢查。

關於資源默認情況下,我不認爲我足夠了解您的情況以正確回答。您是否期望主資源永遠爲空(創建之前除外)?根據您的使用情況,您可能可以使用非阻塞的Moniter.TryEnter,並返回一個值,讓您知道是否收到該鎖。如果您無法立即獲取鎖創建單例,則可以返回默認值。

+0

是的,有時我們可以返回一些結果而不需要資源。但是,如果資源在那裏,我們將使用它,否則,我們只會返回一些默認值。 – 2012-07-16 18:17:30

+0

我已經閱讀了你鏈接的論文,但是有一些矛盾的信息涉及什麼時候應該使用volatile,何時不應該等等......通常,在基於x86或x64的機器上,你不需要它。但是,我無法確定我將在什麼時候運行硬件,並且需要確保在閱讀時使用獲取柵欄。我想我可以發出一個Thread.MemoryBarrier(),但是這開始使事情難以閱讀。無論如何,感謝您的努力,我會等待,看看是否有其他人接受之前輸入。 – 2012-07-16 18:19:51

+0

似乎volatile在.NET 2.0或更高版本中不是必需的,但由於Mono不提供相同的保證,我選擇安全並使用volatile關鍵字。 – 2012-07-18 14:09:09