(Latest Revision: Sun Apr 2 15:33 PDT 2017 ) semaphoreStyles.txt

Semaphore Styles



There are at least two different 'styles' for using semaphores to enforce "happens-before" constraints among concurrent processes.

As an example, suppose that process P0 controls a robot that needs to walk through a house from one room to another, and that P0 must walk through a double door along the way.

Suppose further that process P1 has to open the left half of the door before P0 walks through it, and that process P2 needs to open the right half of the door before P0 walks through it.

One way to program this would be to create a semaphore #0, initialized to value=0, and program the processes like this:
program for P0: wait twice on semaphore #0; walk through the doorway.
program for P1: open the left half of the door; signal on semaphore #0.
program for P2: open the right half of the door; signal on semaphore #0.
According to the style of the set-up above, it's kind of like semaphore #0 belongs to P0, and P0 waits on it to figure out when it's OK to perform its action (to walk through the door). On the other hand processes P1 and P2 use P0's semaphore (not their own semaphores) to signal when they are finished with their actions.

Another way to program this would be to use two semaphores, semaphore #1 and semaphore #2. The programs would go like this:
program for P0: wait on semaphore #1; wait on semaphore #2; walk through the doorway.
program for P1: open the left half of the door; signal on semaphore #1.
program for P2: open the right half of the door; signal on semaphore #2.
According to this second style, it's kind of like P0 uses semaphores that belong to OTHER PROCESSES to figure out when it's OK to perform P0's action. The other processes use their own semaphores to tell P0 (signal) that they are finished with their actions.

It gets a little more complicated if there's a chain of "happens-before" constraints, but it's much easier to manage the complexity if we pick one of the two styles and stick with it.

For example, suppose it's necessary that P3 unlock the double door before either P1 or P2 can open their halves of the door. Let's say we pick the first style of programming semaphores. In that case we'd have semaphores S0, S1, and S2 (declare them as an array). We'd think of S0 as belonging to P0, S1 belonging to P1, and S2 belonging to P2. The programs would go like this:
program for P0: wait twice on S0; walk through the doorway.
program for P1: wait on S1; open the left half of the door; signal on S0.
program for P2: wait on S2; open the right half of the door; signal on S0.
program for P3: unlock the door; signal on S1; signal on S2
See the consistency? S0 waits on P0 in order to time its action. P1 waits on S1 to time its action. P2 waits on S2 to time its action. The relationship of process #k to semaphore #k is consistent.

If we pick the second style for this problem, then we'd use an array of semaphores S1, S2, and S3, and these programs:
program for P0: wait on S1; wait on S2; walk through the doorway.
program for P1: wait on S3; open the left half of the door; signal on S1.
program for P2: wait on S3; open the right half of the door; signal on S2.
program for P3: unlock the door; signal twice on S3.
Here the relationship is different, but consistent here too: P1 signals on S1 to indicate that it has finished its action. P2 signals on S2 to indicate that it has finished its action. P3 signals on S3 to indicate that it has finished its action.

The point is that it's easier to make sense out of the programming if we number the semaphores according to a certain scheme (like style #1, or style #2, but not a mixture of both) and then write the program to use the semaphores consistent with the numbering and the scheme.