From the MSDN page you referenced:
Because the runtime manages dependencies between data, you can often avoid the requirement to synchronize access to shared data.
What this means is that when you're using dataflow blocks in your code, you usually don't have to worry about synchronization, because the blocks do that for you.
But when you're writing a custom dataflow block, then you do need to handle synchronization yourself. For example, imagine you were implementing BufferBlock
. Calling Post()
on that block has to be synchronized somehow, because two source blocks could call Post()
at the same time. And nobody will handle that synchronization for you, so your implementation of Post()
* would need to use locks or ConcurrentQueue
or something like that.
* Actually, you don't implement Post()
, you implement OfferMessage()
.
But, if I understand your requirement correctly, you can actually implement your block without any manual synchronization, by taking advantage of the synchronization that already exists in TDF. You would implement your block by using two BufferBlock
s, a helper Task
and DataflowBlock.Encapsulate()
:
public static IPropagatorBlock<T, T> CreateDelayedBlock<T>(TimeSpan delay)
{
var source = new BufferBlock<T>();
var target = new BufferBlock<T>();
Task.Run(
async () =>
{
while (await source.OutputAvailableAsync())
{
T item;
if (source.TryReceive(out item))
{
await Task.Delay(delay);
await target.SendAsync(item);
}
else
{
// this shouldn't happen
// nobody else should be able to receive from source
}
}
// TODO: if source failed, fail target
target.Complete();
});
return DataflowBlock.Encapsulate(source, target);
}