2011-08-24 19 views
2

我被要求在類的線程內安全地使字典安全。以同樣的方法寫入兩個.net字典時的線程安全性

我的第一個建議是實現一個線程安全的字典中,.NET開發者社區已經工作之上,但遭到拒絕。

的代碼是這樣的:

class Example() 
{ 
    Dictionary<string, string> dic1; 
    Dictionary<string, string> dic2; 
    public void Example() 
    { 
     dic1 = new Dictionary<string,string>(10); 
     dic2 = new Dictionary<string,string>(10); 
    } 

    public string Method1(string param1) 
    { 
      if(dic1.ContainsKey(param1)) 
      { 
       return dic1[param1]; 
      } 

      if(IsValidParam(param1)) 
      { 
       dic1.Add(param1, param1); 
       return param1; 
      } 

      try 
      { 
       var params = GetValidParams(param1); 
       if(params.Count > 0) 
       { 
        foreach(var param in params) 
        { 
         if(!isValirParam(param) 
          continue; 

         dic1.Add(param1, param); 

         if(!dic2.ContainsKey(param1)) 
         { 
          dic2.Add(param, param1); 
         } 

         return param; 
        } 
       } 
       else 
       { 
        dic2.Add(param1, param1); 
        return param1; 
       } 
      } 
      catch(Exception ex) 
      { 
       ..... 
      } 

      return param1; 
    } 
} 

這僅僅是那些讀寫同樣的方法內同時訪問該字典的多種方法之一。

我想對重構並在每個添加和返回使用「ReaderWriterLockSlim」,但我不知道這是怎麼回事,使這個線程安全的。

你有什麼想法如何解決這個問題?我打開的建議...提前

感謝您的時間

+0

查看[ConcurrentDictionary](http://msdn.microsoft.com/zh-cn/library/dd287191.aspx)。也許它會覆蓋你的需求。 – Pashec

+0

由於針對一個字典的操作取決於另一個字典中的值的測試,因此ConcurrentDictionary有所幫助,但本身似乎不足。 – hatchet

+0

現在我堅持使用框架3.5,直到明年我們纔會移動到4.0。\抱歉不要提及 – hyeomans

回答

3

在這種情況下,保證你會得到你所期望的最簡單的方法是使用lock

class Example() 
{ 
    Dictionary<string, string> dic1; 
    Dictionary<string, string> dic2; 
    private Object syncRoot; 
    public void Example() 
    { 
     dic1 = new Dictionary<string,string>(10); 
     dic2 = new Dictionary<string,string>(10); 
     syncRoot = new Object(); 
    } 

    public string Method1(string param1) 
    { 
     lock(syncRoot) { 
      if(dic1.ContainsKey(param1)) 
      { 
       return dic1[param1]; 
      } 

      if(IsValidParam(param1)) 
      { 
       dic1.Add(param1, param1); 
       return param1; 
      } 

      try 
      { 
       var params = GetValidParams(param1); 
       if(params.Count > 0) 
       { 
        foreach(var param in params) 
        { 
         if(!isValirParam(param) 
          continue; 

         dic1.Add(param1, param); 

         if(!dic2.ContainsKey(param1)) 
         { 
          dic2.Add(param, param1); 
         } 

         return param; 
        } 
       } 
       else 
       { 
        dic2.Add(param1, param1); 
        return param1; 
       } 
      } 
      catch(Exception ex) 
      { 
       ..... 
      } 

      return param1; 
      } 
    } 
} 

注意,這將會使事情更慢(鎖具有一些開銷,尤其是你不會有兩個線程同時執行lock'd塊內的任何東西),但它可以確保線程2運行此方法不能在Thread1測試一個值和嘗試使用該測試的結果來執行某些操作時發生變化。它也不需要.net 4,所以你可以使用它。

編輯 - 這也是值得一提的是,如果您有任何修改字典任何其他方法,你會想要鎖定他們以同樣的方式。關鍵在於,在任何特定時刻只有一個線程可以搞亂東西。

+0

會阻止呼叫: 'var params = GetValidParams(param1);'? – hyeomans

+0

@YeomansLeo只有當GetValidParams再次調用Method1時。這是一個鎖定的東西變得棘手的地方,你想更有選擇地使用它,然後我做了(而不是隻是包裝整個方法)。但由於該代碼並不在原始示例中,我只是想以直接的方式進行演示。 :)本質上,鎖定命令指出,除非先到那裏的任何人退出塊,否則其他線程不能通過lock()。它不會阻塞一個不相關的方法,除非在那裏使用相同的鎖定對象(在這種情況下是syncRoot)中有一個鎖。 – Tridus

+0

我應用了這個,我做了一些重構,我得到了foreach語句範圍之外的字典的修改。感謝您的答案! – hyeomans

0

在.NET 4已經有ConcurrentDictionary<T,V>

+2

這並不能解決這個問題,因爲它們中的兩個被同時處理。只是讓字典自己線程安全並不會使整個操作線程安全。 – Tridus

+0

我堅持到現在的框架3.5,我們將不會移動到4.0,直到明年= \抱歉不提, – hyeomans

+0

@Tridus:由於操作只是將它們添加到字典,我不知道爲什麼它不是。顯然,他不能僅僅用'ConcurrentDictionary'來替換'Dictionary'的每個實例 – Marc

0

Tridus說你幾乎不得不把Method1的全部內容包裝在lock。但是,這可能是ReaderWriterLockSlim實際可能有所幫助的一種情況。您可以在dic1的初始查找中讀取鎖定。如果成功,那麼你可以在沒有采取獨佔寫鎖的情況下進行救助。如果查找失敗,則升級到寫入鎖定。當然,你必須進行測試,但如果最初的查找預計會在大多數時間成功,那麼你可以獲得很多併發性。