Producer/consumer queues in C#

What is a producer/consumer queue

In a restaurant there are chefs in the kitchen who wait for orders from customers. As soon as a customer orders something, they (the chefs) make it and serve it to them (the customer). A producer/consumer queue is the same. There are workers who wait for a “job” to be entered into the queue and then process it when it is entered. The advantage of this method is that the workers consume negligible resources when they wait for a job to be added to the queue. So, “jobs” can be finished as soon as possible.

One of the advantages of this approach is that the class which adds the jobs to the queue (the customer) doesn’t have to wait for the workers (the chefs) to finish what they are doing. It will keep inserting the jobs (orders) and the workers (chefs) can take their time processing it (cooking the order).

How do we accomplish this in C# you ask? Simple. The workers will check a job queue to see if anything has been inserted. If they find that there is a job waiting to be processed, then they will remove it from the queue and process it. This way, two workers won’t end up working on the same job. If there are no jobs in the queue then the worker will go to sleep and wait for a signal to wake up when something is added to the queue. The “job manager” or the class that adds the jobs, will insert nulls if it is done adding jobs.

If that was hard to understand, let me explain it in another way. The restaurant will hire 20 chefs and 1 waiter. The customers will place their orders with the waiter. A chef will ask the waiter if he needs to cook anything for a customer. If the waiter says, “Yes, a customer ordered lamb curry” then the chef will start cooking lamb curry. If the orders of all customers have been cooked (or are being cooked by some other chef), then the chef will go to sleep and ask the waiter to wake him up if a customer orders something. However, the waiter will not wake up a specific chef. He will wake up all the chefs when an order comes in. The chef who wakes up first will start cooking and the rest of them will go back to sleep (and ask the waiter to wake them up if any other order comes in). At the end of the day, the waiter will give blank orders signaling to the chefs that they are done for the day.

Now that we know what a producer/consumer queue is, let’s see how we can implement it in C#.

Frist we will take a look at the class which will “consume” the jobs – the resaurant containing the chefs and the waiter.

[csharp]
using System;
using System.Threading;
using System.Collections.Generic;

public class WorkerQueue : IDisposable
{
/* We will store our worker threads in this list. */
private List threads = new List();
/* The number of worker threads to use */
private int threadsToUse = 20;
/* synchronization lock */
private object locker = new object();
/* The queue in which jobs are stored */
private Queue jobs = new Queue();
/* wait handle – used to wake up sleeping threads and to make them wait (sleep) */
EventWaitHandle wh = new AutoResetEvent(false);

/* public variable for accessing threadsToUseProperty */
public int ThreadsToUse { set {threadsToUse=value;} get { return threadsToUse; } }

/* The constructor of this class */
public void WorkerQueue()
{
/* In the constructor, we will start worker threads, which will
* wait for a job to be entered into the queue.
*/
for (int i; i 0)
{
item = jobs.Dequeue();
/* return if a null is found in the queue */
if (item == null) return;
}
}
if (item != null)
{
/* if a job was found then process it */
Console.WriteLine(item);
}
else
{
/* if a job was not found (meaning list is empty) then
* wait till something is added to it
*/
wh.WaitOne();
}
}
}

/* When the object of this class is about to be removed from memory
* we will signal all the worker threads to stop by inserting nulls in the queue
* and then we will wait for them to finish the jobs already in the queue
*
* Letting everyone know we are done for the day
*/
public void Dispose()
{
for (int i=0; i

Comments

2 responses to “Producer/consumer queues in C#”

  1. Kris Avatar
    Kris

    Hi,

    I find this article of yours very helpful. Yet I have a question. I wasn’t able to see how you would call the Dispose method. Do you have any idea on how to call it without user intervention?

    Thanks!

  2. Larry Cohen Avatar
    Larry Cohen

    This example is confusing, because intuitively the chefs would be the producers, since we all know that chefs produce food. However, the real producers are the customers, who we would normally think of as consumers, since they are producing the orders. But once that is realized, the example is helpful. Thank you.

Leave a Reply

Your email address will not be published. Required fields are marked *