2009-04-08 70 views
1

我在多線程應用程序中有一個通用字典;爲了實現一個鎖,我創建了一個屬性。線程:鎖定通用字典

static object myLock=new object(); 
Dictionary<key,SomeRef> dict=new Dictionary<key,SomeRef>(); 

public Dictionary<key,SomeRef> MyDict{ 
     get{ 
     lock(myLock){ 
     return dict; 
     } 
    } 
} 

現在,如果我寫的代碼#1

MyDict.TryGetValue 

或CODE#2

var result=MyDict.Values; 
foreach(var item in result){ 
//read value into some other variable 
} 

因此,雖然即時運行過程中出現的代碼1或2,並在同一時間,如果其他線程嘗試在字典上做一些寫操作,比如..clear dict或添加新項目。那麼,這個解決方案將是線程安全的(使用一個屬性)。 如果不是,那麼是否有其他方法可以做到這一點。

當我說寫操作時,如果不是創建鍵和賦值,可以通過屬性chek key exoist引用該字典。 (因此我沒有在財產中使用setter)

回答

4

不,這不會是線程安全的。

鎖只鎖定獲取對字典的內部(字典)實例的引用。當用戶嘗試添加到字典或從字典中讀取時,它不會鎖定。

如果您需要提供線程安全訪問,我會建議保持字典不公開,並使您自己的方法從字典中獲取/設置/添加值。這樣,您就可以將鎖定在適當的位置以保護您所需的粒度。


這將是這個樣子:

public bool TryGetValue(key thekey, out SomeRef result) 
{ 
    lock(myLock) { return this.dict.TryGetValue(thekey, out result); } 
} 
public void Add(key thekey, SomeRef value) 
{ 
    lock(myLock) { this.dict.Add(thekey, value) } 
} 
// etc for each method you need to implement... 

這裏的想法是,你的客戶直接使用你的類,和你的類處理的同步。如果你期望他們遍歷這些值(比如你的foreach語句),你可以決定是否將這些值複製到一個List中並返回它,或者直接提供一個枚舉器(IEnumerator<SomeRef> GetValues())等。

3

不,這個將不安全,因爲唯一的代碼是locked是檢索代碼。什麼,你需要做的是

lock(MyDict) 
{ 
    if(MyDict.TryGetValue()... 
} 

lock(MyDict) 
{ 
    foreach(var item in MyDict.Values) ... 
} 

的基本思想是鎖()塊中附上您的工作代碼。

+0

嗨亞當謝謝。 lock(MyDict){if(MyDict.TryGetValue()...} 和 lock(MyLock){if(MyDict.TryGetValue()...} – 2009-04-08 17:28:39

2

實現不保證是線程安全的,因爲它是。爲了線程安全,併發讀/寫必須全部由鎖保護。通過發佈對內部字典的引用,您很難控制誰訪問資源,因此您不能保證調用者將使用相同的鎖。

一個好方法是確保您試圖同步訪問的資源完全封裝在您的類型中。這將使得更容易理解和推理該類型的線程安全性。