[英]Using C# ConcurrentBag<T> with multiple producers and a single consumer
我遇到了多個線程正在創建一個ICollection對象的情況。 ConcurrentBag似乎是最好的(?)解決方案,因為-1)每個線程將擁有自己的本地隊列,並且2)線程不需要進行通信-它們是獨立的。 到目前為止,一切都很好,但是事實是我需要從該方法返回一個ISet(在所有生產者都終止之后)。 即使當前的ConcurrentBag實例是不同的(由於應用程序的邏輯得到保證),我仍然需要將其轉換為ISet,例如HashSet。 至此,不再有生產者。 現在是真正的問題:
迭代ConcurrentBag時,調用線程是否將為不在線程本地隊列中的每個項目獲取鎖? 還是每個線程會抓住一次鎖? 另外,僅迭代bag和調用bag.Distinct()顯式地,鎖定方式之間的內部實現是否有所不同?
看一下ConcurrentBag
的源代碼: http : //referencesource.microsoft.com/#System/sys/system/collections/concurrent/ConcurrentBag.cs,537a65e966c1c38d
遍歷袋子會觸發對FreezeBag
的調用。 此方法調用AcquireAllLocks
,它瀏覽每個線程的隊列並設置一個鎖:
/// <summary>
/// local helper method to acquire all local lists locks
/// </summary>
private void AcquireAllLocks()
{
Contract.Assert(Monitor.IsEntered(GlobalListsLock));
bool lockTaken = false;
ThreadLocalList currentList = m_headList;
while (currentList != null)
{
// Try/Finally bllock to avoid thread aport between acquiring the lock and setting the taken flag
try
{
Monitor.Enter(currentList, ref lockTaken);
}
finally
{
if (lockTaken)
{
currentList.m_lockTaken = true;
lockTaken = false;
}
}
currentList = currentList.m_nextList;
}
}
每個線程將獲取一次鎖,而不是每個項目一次。
迭代或調用Distinct
都將調用GetEnumerator
方法,因此沒有什么區別。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.