Reputation: 924
The dataflow library has this option I'm attempting to understand: ExecutionDataflowBlockOptions.SingleProducerConstrained
I put together a test of it's functionality. To my surprise, it seems to drop messages. Why does this not throw an exception instead of dropping messages?
[TestMethod]
public void ExecutionDataflowOptions_SingleProducerConstrained()
{
//The failure does not happen each time, so I run it a few times.
for (int iter = 0; iter < 100; iter++)
{
//Create two buffers and one action block.
var buffer1 = new BufferBlock<int>();
var buffer2 = new BufferBlock<int>();
var input = new List<int>(); //A reference type, to be changed by the action block
var transform = new ActionBlock<int>(i => input.Add(i)
, new ExecutionDataflowBlockOptions() { SingleProducerConstrained = true });
buffer1.LinkTo(transform);
buffer2.LinkTo(transform);
//Add two elements, one from each buffer
buffer1.Post(1);
buffer2.Post(2);
Thread.Sleep(100); //added in test, see end
//Violate the SingleProducerConstrained parameter
Parallel.For(0, 100, i => //0, 1, 2
{
var isAccepted1 = buffer1.Post(i);
var isAccepted2 = buffer2.Post(i);
if (!isAccepted1 || !isAccepted2)
throw new Exception(); //This does not error.
});
//Ensure the transform completes (likely not necessary)
transform.Complete();
transform.Completion.Wait();
//Account for all the items: 200 from the Parallel.For + 2 initial
if (202 != buffer1.Count + buffer2.Count + transform.InputCount + input.Count)
throw new Exception(); //Debug point
}
}
Upvotes: 3
Views: 937
Reputation: 116548
This flag's purpose is not to enforce whether or not there's a single producer. On the contrary. It's for optimizations you can only do when you state that there's only a single producer so the code doesn't need to enforce that.
When you set this flag some blocks can remove locking and synchronization code and its overhead. But only if you make sure to have a single producer. If you don't there may be race conditions and you may indeed lose messages.
"This property should only be set to true if the code using the block can guarantee that it will only ever be used by one producer (e.g. a source linked to the block) at a time, meaning that methods like Post, Complete, Fault, and
OfferMessage
will never be called concurrently. Some blocks may choose to capitalize on the knowledge that there will only be one producer at a time in order to provide better performance."
From ExecutionDataflowBlockOptions.SingleProducerConstrained Property
Upvotes: 4