使用交换从ConcurrentBag获取所有项目

时间:2015-10-15 15:29:48

标签: c# multithreading concurrency interlocked

我试图从ConcurrentBag一举夺取所有物品。由于该集合上的TryEmpty没有任何内容,我已采用与此处所述相同的方式使用Interlocked.ExchangeHow to remove all Items from ConcurrentBag?

我的代码如下所示:

private ConcurrentBag<Foo> _allFoos; //Initialized in constructor.

public bool LotsOfThreadsAccessingThisMethod(Foo toInsert)
{
    this._allFoos.Add(toInsert);
    return true;
}

public void SingleThreadProcessingLoopAsALongRunningTask(object state)
{
    var token = (CancellationToken) state;
    var workingSet = new List<Foo>();

    while (!token.IsCancellationRequested)
    {
        if (!workingSet.Any())
        {
            workingSet = Interlocked.Exchange(ref this._allFoos, new ConcurrentBag<Foo>).ToList();
        }

        var processingCount = (int)Math.Min(workingSet.Count, TRANSACTION_LIMIT);

        if (processingCount > 0)
        {
            using (var ctx = new MyEntityFrameworkContext())
            {
                ctx.BulkInsert(workingSet.Take(processingCount));
            }
            workingSet.RemoveRange(0, processingCount);
        }
    }
}

问题是这有时会遗漏添加到列表中的项目。我已经编写了一个测试应用程序,可以将数据提供给我的ConcurrentBag.Add方法并验证它是否正在发送所有数据。当我在Add电话上设置断点并检查后ConcurrentBag的计数时,它为零。该项目尚未添加。

我之所以相当积极,因为Interlocked.Exchange来电并没有使用ConcurrentBag的内部锁定机制,因此它在某处丢失了数据在交换中,但我不知道实际发生了什么。

如何在不使用我自己的锁定机制的情况下,一次从ConcurrentBag中抓取所有项目?为什么Add会忽略该项?

1 个答案:

答案 0 :(得分:1)

我认为不需要从ConcurentBag中获取所有项目。您可以通过如下更改处理逻辑来实现与您尝试实现的完全相同的行为(不需要自己的同步或互锁交换):

public void SingleThreadProcessingLoopAsALongRunningTask(object state)
{
    var token = (CancellationToken)state;
    var buffer = new List<Foo>(TRANSACTION_LIMIT);
    while (!token.IsCancellationRequested)
    {
        Foo item;
        if (!this._allFoos.TryTake(out item))
        {
            if (buffer.Count == 0) continue;
        }
        else
        {
            buffer.Add(item);
            if (buffer.Count < TRANSACTION_LIMIT) continue;
        }
        using (var ctx = new MyEntityFrameworkContext())
        {
            ctx.BulkInsert(buffer);
        }
        buffer.Clear();
    }
}