在TryReceiveAll之后使用OutputAvailableAsync的BufferBlock死锁

i3a*_*non 20 .net c# task-parallel-library async-await tpl-dataflow

虽然在工作回答这个问题,我写了这个片断:

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);
Run Code Online (Sandbox Code Playgroud)

生产者应该每隔100毫秒将项目发布到缓冲区,并且消费者应该清除缓冲区中的所有项目并异步地等待更多项目显示.

实际发生的是制作人清除所有项目一次,然后再也不会超越OutputAvailableAsync.如果我切换消费者逐个删除项目,它将作为例外工作:

while (await buffer.OutputAvailableAsync())
{
    object item;
    while (buffer.TryReceive(out item)) ;
}
Run Code Online (Sandbox Code Playgroud)

我误会了什么吗?如果没有,问题是什么?

i3a*_*non 11

这是SourceCore内部使用的错误BufferBlock.它的TryReceiveAll方法不会打开_enableOffering布尔数据成员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
Run Code Online (Sandbox Code Playgroud)

我刚刚使用此拉取请求将其修复在.Net核心存储库中.希望修复程序很快就会在nuget包中找到它.