在处理an answerthis 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# - TryReceiveAll之后,带有OutputAvailableAsync的BufferBlock死锁,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/25339029/

10-13 07:09