Skip to main content

Semaphores (continued)

In the previous lab, we saw how a semaphore is a generalization of a mutex. A semaphore initialized with 1 can be used as a lock because only one thread can access the critical section at a time. However, a semaphore can have much more complex uses since it can take various values, both negative and positive.

When a semaphore is initialized with a positive value x, you can think of it as allowing x threads to enter the critical section. As a thread calls acquire(), x is decremented. When it reaches 0, other potential threads that want to access the critical region will have to wait until the semaphore's value increases to a positive value (i.e., until a thread exits the critical region).

Conversely, when a semaphore is initialized with a negative value like -1, it expects at least two threads to first call release() (to increase the semaphore's value from -1 to 1) before a critical region can be accessed (i.e., another thread can call acquire()). You can imagine a third thread waiting "at the semaphore" for the other two threads to signal it by calling release() when they have "finished their job." You can see an example in the pseudocode below.

Semaphore sem = new Semaphore(-1);

T0T1T2

// wait at semaphore


// after the 2 points


sem.acquire();






// sem = 1, so it can pass


System.out.println("I passed the semaphore!");


do_work1();


sem.release();


// sem = -1 + 1 = 0









do_work2();


sem.release();


// sem = 0 + 1 = 1