A "strong semaphore" is one in which an unblocked thread is guaranteed to get possession of the semaphore. In a "weak semaphore", an unblocked thread must recheck the value of the semaphore variable before it can take possession of the semaphore. A weak semaphore can allow one thread to starve another tread. First, here are "implementations" of strong and weak semaphores that can take on negative values. STRONG WEAK ------ ---- P(s) P(s) { { s = s - 1; s = s - 1; if (s < 0) while (s < 0) { { wait(s); wait(s); } } } } V(s) V(s) { { s = s + 1; s = s + 1; if (s <= 0) if (s <= 0) { { unblockOneThread(s); unblockOneThread(s); } } } } Second, here are "implementations" of strong and weak semaphores that always have a non-negative value. STRONG WEAK ------ ---- P(s) P(s) { { if (s == 0) while (s == 0) { { wait(s); wait(s); } } s = s - 1; s = s - 1; } } V(s) V(s) { { s = s + 1; s = s + 1; unblockOneThread(s); unblockOneThread(s); } } Notice that these implementations of V(s) are simplistic in that they do not check if s has been incremented beyond the range that was declared for s when the semaphore was constructed. Here is an example where the semantics of weak vs. strong semaphores matters. Suppose that semaphore1 is initially unsignaled and that threadA waits on semaphore1 before threadB releases it. If the semaphore is a strong semaphore, then the two threads will alternate their work. However, if the semaphore is a weak semaphore, then threadB could starve threadA. threadA threadB { { while(true) while(true) { { wait(semaphore1); // work // work release(semaphore1); release(semaphore1); wait(semaphore1); } } } } Note that this code does not work properly if threadB releases semaphore1 before threadA waits on it (even if the semaphore is a strong one). This can be fixed by using two semaphores. Initially, both semaphores should be unsignaled. threadA threadB { { while(true) while(true) { { wait(semaphore1); // work // work release(semaphore1); release(semaphore2); wait(semaphore2); } } } }