I’m using a BlockingCollection to implement a producer/consumer pattern. I have an asynchronous loop that fills the collection with data to be processed which can then at a much later time be accessed by the client. The packets arrive sparsely and I would like the polling to be done without using a blocking call to take.
In essence, I’m looking for something like a BeginTake and EndTake that does not exist in the blocking collection so that I can make use of the internal thread pool in a callback. It does not have to be a BlockingCollection by any means. Anything that does what I need would be great.
This is what I’ve got now. _bufferedPackets is a BlockingCollection<byte[]>:
public byte[] Read(int timeout)
{
byte[] result;
if (_bufferedPackets.IsCompleted)
{
throw new Exception("Out of packets");
}
_bufferedPackets.TryTake(out result, timeout);
return result;
}
I’d like this to be something like this, in pseudocode:
public void Read(int timeout)
{
_bufferedPackets.BeginTake(result =>
{
var bytes = _bufferedPackets.EndTake(result);
// Process the bytes, or the resuting timeout
}, timeout, _bufferedPackets);
}
What are my options for this? I do not want to place any thread in a waiting state, since there is lots of other IO stuff for it to process, and I would run out of threads pretty quickly.
Update: I’ve rewritten the code in question to use the async process differently, essentially swapping callbacks based on if there is a waiting request within the timeout limit. This works fine, but still it would be awesome if there was a way to do this without resorting to timers and swapping lambdas around which potentially causes race conditions and is hard to write (and understand). I have solved this also with an own implementation of an async queue, but it would still be awesome if there was a more standard and well tested option.
So there doesn’t look to be a built in option for this, I went out and tried to do my best to make what I wanted as an experiment. Turns out there is a lot of cruft to do in order to make this work roughly as other users of the old async pattern.
I’m not too sure about the synchronization of the
IsCompleteproperty, and I’m not too hot on how thedequeueQueueonly gets cleaned up on subsequentEnqueuecalls. I’m not sure when is the correct time to signal the wait handles either but this is the best solution that I’ve got so far.Please do not consider this production quality code by any means. I just wanted to show the general gist of how I got around to keeping all threads spinning without waiting locks. I’m sure this is full of all kinds of edge cases and bugs but it fulfills the requirements and I wanted to give something back to people who comes across the question.