Let us look at how one might use a semaphore to achieve mutual exclusion when updating a shared variable:
// Global variables (shared between processes):The code for 'removeAUser' is left as an exercise for the reader.
int count; // The shared variable.
// Create a semaphore for mutual exclusion---initialised to 1.
Semaphore mutex = new Semaphore(1);void addAUser(){
register int temp;
wait(mutex); // Start of critical section.
temp = count;
temp ++;
count = temp;
signal(mutex); // End of critical section.
}
Let's look at the case when two processes attempt to update the shared
variable:
process #1 | process #2 | mutex counter | blocked processes | critical section processes |
---|---|---|---|---|
1 | ||||
wait(mutex) | 0 | P2 | ||
wait(mutex) | 0 | P1 | P2 | |
blocked | critical code | 0 | P1 | P2 |
blocked | signal(mutex) | 1 | P1 | |
(unblocked) | 0 | P1 | ||
critical code | 0 | P1 | ||
signal(mutex) | 1 | |||
wait(mutex) | 0 | P2 | ||
critical code | 0 | P2 | ||
signal(mutex) | 1 |
The example above makes use of a 'binary semaphore'. It only ever has the values 0 and 1 (can you see why). Binary semaphores are ideal for mutual exclusion because we want to ensure that only one process is ever in a critical section.