簡體   English   中英

使用C#ConcurrentBag <T> 有多個生產者和一個消費者

[英]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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM