Locks: primitive, can get the job done Semaphores: much better control, "passing the baton", requires very precise and tedious code for maximum power. Monitors: much easier to use than semaphores (not always trivial, though). And, it works in the framework of an object-oriented programming. A monitor is an object so that ONLY ONE thread may be active in a monitor method at any time. If a monitor has 100 methods and 1000 threads within those methods, only one of these are active. (There's only one thread moving in a monitor at any time. It is not one thread per method, it is one thread for the whole monitor.) A monitor has condition variables as part of the object. You can specify as many condition variables as you would like. Condition variables are similar to semaphores, but they are not exactly the same. A condition variable has two operations: wait (cond) which locks the current thread on that condition variable. Because this thread is now locked, another thread can be released (so you still have one active thread in the monitor). signal (cond) ** If there is one or more threads waiting on the condition variable, the monitor releases the one that has been waiting the longest. If there no threads waiting on cond, then signal does nothing. (This is different from semaphores work. If you signal a semaphore on which nothing is waiting, then the value of the semaphore increases by one, that the next thread to P the semaphore will not block. In a monitor, waiting on a condition variable ALWAYS causes the thread to block.) ** If I signal a condition variable, does that mean that I now have two active threads in the monitor, myself and the one I just signaled? Yes...except monitors prevent that from happening. There are two basic strategies to prevent this from happening. SIGNAL-AND-WAIT: If I signal a condition variable, then the newly released thread becomes active, and I have to wait. My status is like that of a thread trying to enter the monitor. I'm not waiting on a condition variable, but I still have to wait until my turn rolls around to enter the monitor. ^^^^^ This is the less common strategy and NOT the strategy that we are using in this class. SIGNAL-AND-CONTINUE: If I signal a condition variable, I am still active. The thread I released has to wait until I'm done. That thread is treated like a thread that just called a monitor method. It's not locked on a condition variable, but it still has to wait until the monitor is free. THIS IS THE MOSTLY WIDELY IMPLEMENTED VERSION OF MONITOR, and this will be our class interpretation. You have to keep in mind: when you signal a condition variable, that thread will become active at some future point, but not quite yet. How to parallelize certain algorithms is not always immediately obviouswhen you consider that only one thread is active in the monitor at any given time. But you can use a technique similar to passing the baton to get the monitor to do your bidding. class RWMonitor extends monitor { cond R, W; int nr=0, nrw=0, nw=0, nww=0; void ReadBegin() { if (nw+nww>0) {nrw++; wait (R);} else nr++; } void ReadEnd () { nr--; if (nr==0 && nww > 0) {nww--; nw++; signal (W);} } void WriteBegin () { if (nr + nrw + nw > 0) {nww++; wait (W);} else nw++; } void WriteEnd () { nw--; if (nrw > 0) while (nrw > 0) {nrw--; nr++; signal (R);} else if (nww > 0) {nww--; nw++; signal (W);} } RWMonitor mon; main () { ... //I'm reading mon.ReadBegin(); read from the database mon.ReadEnd(); //I'm writing mon.WriteBegin(); write to the database mon.WriteEnd(); Doing a rollercoaster with monitors. I have a car that can hold C people. The car will wait until C people board, and then will release the people when the ride is over. People stand in line if there is no opening in the car, and will wait until there is an opening in the car. Mon::Board () { if (nr==C) { nrw++; wait (board); ...board... if (nr==C) { signal (car); } else if (nrw > 0) { nrw--; nr++; signal (board); } } else { nr++; if (nr==C) signal (car); }