我在.NET8中try BlockingCollection<T>(作为一个队列),有时我会得到一个异常:

"System.InvalidOperationException: The collection argument is empty and has been marked as complete with regards to additions."

代码示例:

    private static void TestMethod()
    {
        using BlockingCollection<DummyClass> queue = new BlockingCollection<DummyClass>();

        var task = Task.Run(() =>  //Produce
        {
            for (int i = 0; i < 10000000; i++)
            {
                queue.Add(new DummyClass());
            }
            queue.CompleteAdding();

        });

        int counter = 0;
        try
        {
            while (!queue.IsCompleted)  //Consume
            {
                DummyClass item = queue.Take(); // <-- Sometimes exception here
                counter++;
            }

            Console.WriteLine($"counter={counter} ");
        } 
        catch (Exception ex)
        {
            Console.WriteLine("Error:" + ex.ToString());
        }
    }

IsComplete声明"此集合是否已被标记为已完成添加and is empty."

因此,只要尚未调用CompleteAdding(),Take()就应该被阻塞,并且当CompleteAdding()已经被调用并且队列为空时,"!quee.IsComplete"就应该返回FALSE.

我遗漏了什么?

任何帮助都将不胜感激.

运行在Windows 11上的VS2022 17.8.5中.

推荐答案

你有一个线程比赛;想象一下:

  • 队列为空
  • 线程A即将调用queue.CompleteAdding();
  • 线程B即将判断 while (!queue.IsCompleted)
  • 线程B获得一些周期,发现它当前未完成
  • 线程A得到一些周期,将队列标记为完成
  • 线程B得到一些周期,调用Take()

和动臂

解决方案:使用TryTake

Csharp相关问答推荐

PredicateBuilder不是循环工作,而是手动工作

应该使用哪一个?"_counter += 1 OR互锁增量(ref_counter)"""

EF Core在请求列表时忽略列,但在按ID获取时包含

数组被内部函数租用时,如何将数组返回给ArrayPool?

为什么C#Bigbit不总是相同的比特长度?

System.Text.Json数据化的C#类映射

使用LayoutKind在C#中嵌套 struct .显式

持有者安全定义未显示在Swagger.NET 8中

try 使用C#ASP.NET收集WMI信息时访问被拒绝,但在PowerShell中工作

按需无缝转码单个HLS数据段

Blazor Server.NET 8中的Blazore.FluentValidation问题

使用C#和.NET 7.0无法访问Cookie中的数据

我的命名管道在第一次连接后工作正常,但后来我得到了System.ObjectDisposedException:无法访问关闭的管道

C#LINQ延迟执行和嵌套方法

Maui:更改代码中的绑定字符串不会更新UI,除非重新生成字符串(MVVM)

try 访问字典中的模拟对象时引发KeyNotFoundException

Xamarin中出错.表单:应用程序的分部声明不能指定不同的基类

同时通过多个IEumable<;T&>枚举

ASP.NET核心中的验证错误-该字段为必填字段

将ValueTask发送给调用者