2012-07-23 62 views
7

以下假設對於此代碼是否有效?我在代碼中加入了一些背景信息,但我認爲它不相關。在運行時在ASP.NET中創建動態鎖定

假設1:由於這是一個單一的應用程序,我假設它將由單個進程處理。因此,線程之間共享靜態變量,並靜態聲明我的鎖對象集合是有效的。

假設2:如果我知道該值已經在字典中,我不需要鎖定讀取。我可以使用一個ConcurrentDictionary,但是我相信這個將是安全的,因爲我沒有列舉(或刪除),並且當我呼叫UnlockOnValue()時,該值將存在並且不會改變。

假設3:我可以鎖定Keys集合,因爲該引用不會更改,即使基礎數據結構不會更改。

private static Dictionary<String,Object> LockList = 
    new Dictionary<string,object>(); 

private void LockOnValue(String queryStringValue) 
{ 
    lock(LockList.Keys) 
    { 
     if(!LockList.Keys.Contains(queryStringValue)) 
     { 
      LockList.Add(screenName,new Object()); 
     } 
     System.Threading.Monitor.Enter(LockList[queryStringValue]); 
    } 
} 

private void UnlockOnValue(String queryStringValue) 
{ 
    System.Threading.Monitor.Exit(LockList[queryStringValue]); 
} 

那我就用這個代碼,如:

LockOnValue(Request.QueryString["foo"]) 
//Check cache expiry 
//if expired 
    //Load new values and cache them. 
//else 
    //Load cached values 
UnlockOnValue(Request.QueryString["foo"]) 

背景:我是根據在查詢一個用戶定義的變量下載數據在創建ASP.NET應用程序串。值的數量將非常有限。我需要在指定的時間段內緩存每個值的結果。

方法:我決定使用本地文件緩存數據,這不是最好的選擇,但我想嘗試一下,因爲這不重要,性能也不是什麼大問題。我爲每個選項使用了2個文件,其中一個包含緩存過期日期,另一個包含數據。

期:我不確定什麼是最好的鎖定方式,而且我也不太熟悉.NET中的線程問題(我選擇這種方法的原因之一)。基於可用的內容以及我閱讀的內容,我認爲上述內容應該可行,但我不確定並希望得到第二個意見。

+1

使用'HttpRuntime.Cache'有什麼問題? – scottm 2012-07-23 18:05:02

+0

這是我的第一選擇,但表現奇怪。這可能是因爲我的頁面擦除了響應並返回了一個文本文件,但是在遇到類似的問題後,我沒有深入地發現所有的互聯網,沒有爲我工作的答案。唯一沒有涉及的是IIS配置以及緩存配置是否正確。我以後可能會這樣做,但這是非關鍵的代碼,這引發了我想要的答案,即使它不是最好的架構。 – Kendrick 2012-07-23 18:19:54

+0

我正試圖在緩存方法結果的地方實現一個非常類似的解決方案。我還需要一種創建不同緩存鎖的方法,我想知道您的解決方案是否經受住了時間的考驗,歡呼。 – 2014-02-04 16:29:23

回答

6

您目前的解決方案看起來不錯。我會改變的兩件事:

1:UnlockOnValue需要在finally塊中。如果拋出異常,它將永遠不會釋放它的鎖。

2:LockOnValue效率有點低,因爲它執行了兩次字典查找。對於小字典來說這不是什麼大問題,但對於較大的字典,您將希望切換到TryGetValue。

此外,您的假設3持有 - 至少現在。但Dictionary合約不保證Keys屬性總是返回相同的對象。由於不依賴於此很容易,我建議不要這樣做。每當我需要一個對象鎖定時,我只是爲了這個唯一目的而創建一個對象。例如:

private static Object _lock = new Object(); 
+0

我應該在僞代碼中指定它,但我在finally塊中指定了它。我從來沒有想過TryGetValue,但這可能是一個更好的選擇。字典將很小,但仍然值得思考。 – Kendrick 2012-07-24 17:56:51

+0

是的,這是我的寵物看到一個呼叫Contains,然後打電話給[],因爲他們都必須找到元素。 – bmm6o 2012-07-24 18:24:30

1

lock只有一個過程的範圍。如果你想跨越進程,你必須使用像Mutex(named)這樣的基元。

lockMonitor.EnterMonitor.Exit相同。如果你也做Monitor.EnterMonitor.Exit,它是多餘的。

您不需要鎖定讀取,但您必須鎖定檢查該值是否存在並添加它的「事務」。如果您不鎖定該系列指令,則在您檢查密鑰時以及添加並添加密鑰時會出現其他內容,從而導致出現異常。你正在做的鎖就足夠了(你不需要額外的呼叫進入和退出 - 鎖會爲你做)。

+0

我假設這個應用程序的所有線程都將來自同一個進程。我所看過的文檔和例子都指出了這種情況,儘管我仍然不能100%確定。這實際上是我不確定的第二個假設。我認爲第一個是正確的,第三個可能是正確的,但沒有理由只爲字典創建一個鎖對象(即可能工作,但可能是錯誤的代碼) – Kendrick 2012-07-24 14:11:38

+0

如果它是一個應用程序,並且所有線程都是在這個過程的一個實例中,鎖適合這種情況。 – 2012-07-24 14:33:23