I implements a producer-consumer pattern using C#'s TPL. The scenario is described as below.
I have a task who produces jobs to a BlockingCollection. The collection has a capacity limit, say, 3 jobs maximally. I have two consumer tasks who try to get jobs from the collection and execute them. I also implement a cancellation to the producer and consumers. For producer, when it detects cancellation, it will call BlockingCollection.CompleteAdding(), which allows the consumers to finish waiting.
Now it is possible that:
Time 1: The producer puts 2 jobs in the collection;
Time 2: Two consumers grab the jobs and run themselves;
Time 3: The producer puts another 3 jobs in the collection. Since it meets the capacity of the collection, the producer goes to asleep;
Time 4: The cancellation happens on the two consumers. They stop.
Now the producer sleeps forever because no one works on the jobs. How to handle the cancellation on consumers so they can sort of wake up the producer?
What I can think of is put the below code in the cancellation handler of the consumers.
lock(BlockingCollection){
if(BlockingCollection.BoundedCapacity == BlockingCollection.Count) BlockingCollection.Take();
}
Since there are more than one consumer, it has to lock the collection. The extra take is only necessary when the BlockingCollection.BoundedCapacity equals to the number of items in it. This extra take will empty one slot in the collection and thus trigger the producer to wake up, detect the cancellation itself.
Is this correct?