c# - 将 C# ConcurrentBag<T> 与多个生产者和单个消费者一起使用

标签 c# .net multithreading concurrency locking

我遇到了一种情况,多个线程正在创建一个 ICollection 对象。 ConcurrentBag 似乎是最好的(?)解决方案,因为 - 1)每个线程都有自己的本地队列,2)线程不需要通信 - 它们是独立的。到目前为止一切顺利,但事实是我需要从此方法返回一个 ISet(在所有生产者终止之后)。即使当前的ConcurrentBag实例IS不同(由于应用程序的逻辑而保证),我仍然需要将其转换为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 方法,因此没有区别。

关于c# - 将 C# ConcurrentBag<T> 与多个生产者和单个消费者一起使用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30866665/

相关文章:

c# - TypeLoadException : Method 'Create' in type . ..没有实现(错误如下)

c# - c#中列表的XML序列化/反序列化

c# - Linq-to-Sql SubmitChanges 不更新字段......为什么?

.net - 如何阻止Winforms面板滚动?

c# - AuthenticationHeaderValue 与 NetworkCredential

c# - 从 C# 2.1 驱动程序正确关闭 MongoDB 数据库连接?

c# - 最近一篇关于 Java EE 和 .NET 比较的好文章?

python - Django 数据库和线程

multithreading - 从多个线程同时从单个串行端口读取和写入

python - 用线程在tkinter中的进度条