views:

40

answers:

2

I am using a multi-threaded producer/consumer queue with a single (very fast) producer and many, much slower, consumers. Each consumer has exclusive access to a piece of physical hardware, such as a phone line. The producer runs on the main thread and each consumer runs on its own thread. Each consumer thread is created and initialized when the program starts up.

What I am attempting to do is always use the first consumer if available, if it is busy then use the second consumer. If the first two are busy then use the third and so on. If consumer two is busy and consumer one is now ready, then it should use the first.

Simply locking the queue and using monitor.pulse when an item is en-queued in the producer and monitor.wait in the consumer (with the wait condition being the queue is empty) does not work since each consumer enters the wait queue at the mercy of the thread scheduler. This results in each consumer being used in a round-robin fashion.

Is there an easy way to pull this off?

EDIT:

Just implemented this by creating a list of hardware-bound objects that the consumer threads lock, waiting if there are none available, then passing the work item to the acquired device. Once the consumer is finished with the device, it sets it as available and pulses a waiting thread (if any).

A: 

It is a bit hard to see what would be wrong with round-robin. Assumption: what you really want to do is re-use the same hardware device as soon as it is available. So make that work, let each consumer thread negotiate what device to use. Should be simple with a List<bool> protected by a lock to indicate which device is available.

Hans Passant
Your assumption is correct: see edit for how I implemented this.
Hugh Jeffner
A: 

You could have one lock object for each thread and when the producer creates a new job, it tries the locks sequentially using Monitor.TryEnter() until it succeeds.

svick