c# - BufferBlock 在 TryReceiveAll 之后与 OutputAvailableAsync 死锁

标签 c# .net task-parallel-library async-await tpl-dataflow

在处理 an answer 时至 this question ,我写了这个片段:

var buffer = new BufferBlock<object>();
var producer = Task.Run(async () =>
{
    while (true)
    {
        await Task.Delay(TimeSpan.FromMilliseconds(100));
        buffer.Post(null);
        Console.WriteLine("Post " + buffer.Count);
    }
});
var consumer = Task.Run(async () =>
{
    while (await buffer.OutputAvailableAsync())
    {
        IList<object> items;
        buffer.TryReceiveAll(out items);
        Console.WriteLine("TryReceiveAll " + buffer.Count);
    }
});
await Task.WhenAll(consumer, producer);

生产者应每 100 毫秒将项目发送到缓冲区,而消费者应清除缓冲区中的所有项目并异步等待更多项目出现。

实际发生的是生产者清除所有项目一次,然后再也不会超出 OutputAvailableAsync。如果我将消费者切换为一件一件地移除元素,它会按异常(exception)情况工作:

while (await buffer.OutputAvailableAsync())
{
    object item;
    while (buffer.TryReceive(out item)) ;
}

我是不是误会了什么?如果不是,问题是什么?

最佳答案

这是 SourceCore 中的一个错误,被 BufferBlock 内部使用。它的 TryReceiveAll 方法不会打开 _enableOffering bool 数据成员,而 TryReceive 会。这导致从 OutputAvailableAsync 返回的任务永远不会完成。

这是一个最小的复制:

var buffer = new BufferBlock<object>();
buffer.Post(null);

IList<object> items;
buffer.TryReceiveAll(out items);

var outputAvailableAsync = buffer.OutputAvailableAsync();
buffer.Post(null);

await outputAvailableAsync; // Never completes

我刚刚用 this pull request 在 .Net 核心存储库中修复了它.希望修复程序很快就会出现在 nuget 包中。

关于c# - BufferBlock 在 TryReceiveAll 之后与 OutputAvailableAsync 死锁,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25339029/

相关文章:

c# - 如何正确地将字符串转换为单词和标点符号列表?

c# - 将 .NET 应用程序转换为 x86 native 代码

c# - 如何使用 Global.asax 来使用 Local_resources?

c# - PropertyGrid 替代品

C# Parallel.For 和未初始化数组

javascript - 如何从 Json 字符串中删除转义字符?

c# - 在c#(VS2015)中查看垃圾回收历史

c# - 我如何告诉 Moq 返回任务?

c# - Google 帐户问题 - 无法在电子表格上书写

c# - Task.WhenAll 未完成