2015-05-21 27 views
2

我製作了一個應用程序,其中還包含一個文件夾/文件掃描程序。我遇到了線程結構的問題。多線程列表模式建議

工作原理: 對於每個文件夾/文件,它會發現它啓動一個線程。每個線程中都有一個函數,它使用一個列表來檢查是否找到了類似的項目,以便它可以添加到現有項目中。如果沒有找到,它會將該項目添加到前面提到的列表中。線程並行執行(異步)。

問題: 因爲它是異步的,它有時會在列表檢查中失敗。這是因爲檢查和添加到列表之間有一段時間。可能發生的事情是,檢查返回,沒有類似的項目,當然是。這將導致列表中出現相同的項目。

我也已經讓線程彼此等待。我非常喜歡它在前端的效果。 (項目很好地實時添加到列表中)。但是這需要很長的時間來處理很多文件夾/文件。

現在我正在考慮在函數之間進行混合,但我真的很希望看到異步線程的速度和等待每個線程的安全性。

有人有什麼想法嗎?

回答

3

您應鎖定檢查列表並添加值的整個代碼部分。

事情是這樣的:

private void YourThreadMethod(object state) 
{ 
    // long taking operation 

    lock (dictionary) 
    { 
     if (!dictionary.ContainsKey(yourItemKey)) 
     { 
      // construct object, long taking operation 

      dictionary.Add(yourItemKey, createdObject); 
     } 
    } 
} 

這樣,每個線程將不得不等待,直到list是免費使用的。如果你想要一個更高級的解決方案,你可以閱讀ReaderWriterLockSlim這個類,它提供了一個更精細的解決方案。

+0

爲什麼'ConcurrentDictionary '? –

+0

@AndreasNiedermair:因爲這並不妨礙檢查與延遲添加問題。 –

+0

你只是圍繞一個非原子操作構造一個鎖,使其成爲「原子」 - 與TryAdd有什麼不同?我錯過了什麼 - *這將導致相同的項目發生在列表中。*這正是「TryAdd」的原因......? –

0

我會考慮在C#中使用thread safe collections之一。對於你的情況,像ConcurrentBag將比使用鎖更有效。

如果在檢查和添加之間存在時間延遲,則可以使用ConcurrentDictionary。它有一個TryAdd方法,如果具有相同密鑰的項目已經在字典中,將返回false

+0

當檢查和添加之間有時間時,這不是一個解決方案。 –

+0

不錯,你可以用'ConcurrentDictionary'來做到這一點,不過它會執行檢查並添加一個原子操作。 –

+0

@NedStoyanov我不會把它稱爲* atomic *本身,因爲它不是一個操作。內部使用鎖定機構來確保不受干擾。鎖的獲取確實是一個原子操作(取決於處理器),但'TryAdd'只是*線程安全的:) –

2

最光滑的方法是ConcurrentDictionary<string, byte>的使用時yourItemKey是類型的stringotherwise adapt TKey and use a proper IEqualityComparerimplement IEquatable):

private readonly ConcurrentDictionary<string, byte> _list = new ConcurrentDictionary<string, byte>(); 
private void Foo(object state) 
{ 
    // looong operation 
    this._list.TryAdd(yourItemKey, 0); 
} 
public void Bar() 
{ 
    // this is how to query the content 
    this._list.Keys...; 
} 

背後訣竅是不使用太複雜對象作爲密鑰,這可能需要處置或具有外部引用(我傾向於任何字符串表示形式)以及值的小類型,它只是用作標記。