While working on an answer to this question, I wrote this snippet:
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);
The producer should post items to the buffer every 100 ms and the consumer should clear all items out of the buffer and asynchronously wait for more items to show up.
What actually happens is that the producer clears all items once, and then never again moves beyond OutputAvailableAsync
. If I switch the consumer to remove items one by one it works as excepted:
while (await buffer.OutputAvailableAsync())
{
object item;
while (buffer.TryReceive(out item)) ;
}
Am I misunderstanding something? If not, what is the problem?
Alas, it's the end of September 2015, and although i3arnon fixed the error it is not solved in the version that was released two days after the error was fixed: Microsoft TPL Dataflow version 4.5.24.
However IReceivableSourceBlock.TryReceive(...) works correctly. An extension method will solve the problem. After a new release of TPL Dataflow it will be easy to change the extension method.
usage:
This is a bug in
SourceCore
being used internally byBufferBlock
. ItsTryReceiveAll
method doesn't turn on the_enableOffering
boolean data member whileTryReceive
does. That results in the task returned fromOutputAvailableAsync
never completing.Here's a minimal reproduce:
I've just fixed it in the .Net core repository with this pull request. Hopefully the fix finds itself in the nuget package soon.