October 10, 2007
Apply Critical Sections ConsistentlyExample 1: One Producer, Many Consumers, Using Locks
Imagine we have a single Producer thread that produces a number of tasks for Consumer threads to perform. The Producer pushes the tasks into a shared queue, and finally pushes a special done sentinel to mark the end of the work. The queue object is protected at all times using mutex mut, which the Producer holds only as long as necessary for a single push, so that Consumers can start executing their tasks concurrently with the Producer. For further efficiency, to avoid making the Consumers busy-wait whenever the queue is initially or temporarily empty, the Producer will also signal condition variable cv every time something has been added to the queue:
On the consumption side, the Consumer threads each pull individual tasks off the completed queue. Here, myTask is an ordinary variable local to each Consumer:
// K Consumer threads
//
myTask = null;
while( myTask != done ) {
mut.lock(); // enter critical section
while( queue.empty() ) // if nothing's there, to avoid busy-waiting we'll
cv.wait( mut ); // release and reenter critical section
myTask = queue.first(); // take a copy of the task
if( myTask != done ) // remove it from queue unless it was the sentinel,
queue.pop(); // which we want to leave there for others to see
mut.unlock(); // exit critical section
if( myTask != done )
DoWork( myTask );
}
All of these critical sections are easy to see. This code simply protects the data structure using the same mutex for its entire shared lifetime, and it's easy to check that you did it rightjust look to make sure the code only refers to queue when inside some critical section that holds a lock on mut.
The primary expression of critical sections is the explicit locking done on the mutex. The condition variable is just icing on the cakean optimization that lets us express an efficient wait point in the middle of a locked section so that the Consumer race cars don't have to expend needless energy spinning their tires (in this case, their lock/unlock loop) while waiting for the Producer to give them the green light.
|
|
||||||||||||||||||||||||||||||
|
|
|
|