2016-07-12 111 views
0

我有一個帶有所有資源的基本路徑的文件。例如:代碼會產生競爭狀態嗎?

build/scripts/script1.js 
build/scripts/script2.js 

我當然需要例如基本路徑:

https://example.org/SuperDuperSite/build/scripts/script1.js 

什麼,我希望做的是將文件加載到一個全局字典在與路徑啓動。字典只需要加載一次。不幸的是,據我所知,基本路徑不可用,直到第一個請求。所以在asp.net我必須使用application_beginrequest而不是application_start。現在我不得不面對多線程問題。

這迫使我寫了下面的代碼類型:

lock(_lock) { 
    if (_dictionary == null) { 
     LoadDictionary(); 
    } 
    } 

這將要求每一個請求時,我才真正需要一次加載它。我當然不喜歡這個。出於性能原因,我不想鎖定每一個請求。一個解決方案,交談學院之後,我們想出了:

if (_dictionary == null) 
{ 
    lock(_lock) { 
     if (_dictionary == null) { 
     LoadDictionary(); 
     } 
    } 
} 
這個解決方案,我不會被要求鎖定在每一個請求

左右,但如果多個線程最終獲得這部分在啓動時我會再保護它通過檢查對象是否在鎖內再次爲空。此代碼是否可以工作,還是會遇到競爭狀態?

+0

聽起來很複雜,包括一個基地網址。您是否有理由在啓動時將它加載到字典中? –

+1

你確定你是從正確的角度來攻擊嗎?有沒有理由不能做相對路徑請求? –

+1

雙重檢查鎖定在c#中是安全的。代碼示例中的條件是落後的,但其他條件很好。 –

回答

1

使用雙重檢查鎖時要小心。

是的,它是線程安全的,但在您的特定代碼你可能會遇到一個微妙的臭蟲_dictionary一直由其他線程(傳遞null檢查)實例,但不完全填充還,並且您最終可能會嘗試訪問部分填充的字典。並最終與這兩個中的一個:

  1. 您正在閱讀的字典時丟失的結果,或者更糟
  2. 除非您使用的是ConcurrentDictionary(其中還附帶了性能問題),你可能會同時讀取和寫入字典,並導致死鎖(是的,類已知在許多代碼中導致死鎖)。

一個bool _dictionaryLoaded標誌(雙重檢查),翻轉trueLoadDictionary()年底,可能會更好。

或使用Lazy<>如果您使用的是.NET 4.它更簡潔,您只需傳入LoadDictionary即可用作初始化函數。

編輯:懶惰<>是internally implemented with a double-checked lock