2016-01-04 21 views
0

我有一個擁有多個線程的應用程序,其中每個線程對由GUID引用的資源執行一些操作,其中所述GUID作爲字符串存儲在列表中。隨時在GUID引用的資源上只能執行一個操作。多線程,鎖定和字符串值列表

我想爲此和一個簡單的列表使用鎖定語句。我遇到的問題是,我似乎無法安全地通過檢查來查看列表中是否包含鎖定語句中的GUID,然後使用另一個鎖定語句將其添加到列表中。看起來,當有多個線程時,每個線程都檢查以查看該GUID是否在列表中,並且檢查返回false,它們都會添加GUID(顯而易見的問題)。

此外,我不能將檢查放在與將GUID添加到字符串列表的語句相同的鎖內,因爲如果我這樣做,鎖將被阻止,從而阻止正在處理資源的其他線程將它從列表中刪除(它們無法獲得鎖定)。

我希望你能原諒我原始的例子,但我不知道如何在多線程環境中安全地進行可靠的測試和鎖定。不幸的是,我無權爲我的客戶更改應用程序的設計。

如果你有一個類/圖書館推薦,一個小例子將不勝感激。

private static readonly object _guidLock = new object(); 
private static List<string> guidList = new List<string>(); 

public static bool isGuidLocked(string guid) 
{ 
    lock (_guidLock) 
    { 
     if (guidList.Contains(guid)) return true; 
     return false; 
    } 
} 

public static bool lockGuid(string guid) 
{ 
    while (isGuidLocked(guid)) { } 
    lock (_guidLock) 
    { 
     guidList.Add(guid); 
    } 
    return true; 
} 

public static bool releaseGuid(string guid) 
{ 
    lock (_guidLock) 
    { 
     guidList.Remove(guid); 
    } 
    return true; 
} 

public static void doWorkOnGuid(string guid) 
{ 
    lockGuid(guid); 
    // do something there 
    releaseGuid(guid); 
} 
+0

您是否正在尋找正確的方法或解釋爲什麼您的代碼不太可能正常工作? (您可能希望查看「雙重檢查鎖定」以瞭解如何完成代碼以正確工作) –

+0

我希望更好地理解正確的方法,看看能否正確集成它。 – joelc

回答

3

請勿使用列表。 .NET提供了線程安全的集合。

在這種情況下,您可能需要使用GUID作爲鍵的ConcurrentDictionary

見命名空間:System.Collections.Concurrent

的System.Collections.Concurrent命名空間提供了應在的地方 相應類型的System.Collections中的和System.Collections中 使用幾個 線程安全的集合類。當多個線程同時訪問集合時,通用命名空間爲 。

+0

舉例如何處理上面'lockGuid'中的「等待和添加」情況? – joelc

+1

您不需要手動等待。我想你想在ConcurrentDictionary上使用[TryAdd()](https://msdn.microsoft.com/en-us/library/dd267291%28v=vs.110%29.aspx)方法。如果GUID不存在並被添加,它將返回true,否則返回false。 – Timeout

+0

即while(!TryAdd(...)){}會做我需要的嗎? – joelc

0

使用基於時間戳的併發控制技術來處理這種情況。使用一個靜態變量_guidListUpdateTime,它將保存最新的_guidList修改時間。同樣,爲每個線程分配一個讀取時間標記值。現在,當添加guid列表時,檢查當前線程讀取時間標記是否大於_guidListUpdateTime。如果是,則將guid添加到guidList,否則不要。 https://www.classle.net/book/timestamp-based-protocol