These functions are the practical implementation of the theoretical “P operation” (test and decrement) we discussed earlier.

1. The sem_wait Function

This is the standard blocking function used when a process needs to acquire a resource.

#include <semaphore.h>
 
int sem_wait(sem_t *sem);
// Returns: 0 if OK, -1 on error

How it works:

  1. Test: It checks the current value of the semaphore sem.
  2. Decrement (Lock):
    • If value > 0: It decrements the counter by 1 and returns immediately. The process has successfully “acquired” one unit of the resource.
    • If value == 0: The call blocks (sleeps). The process pauses execution and waits in a queue until some other process increments the semaphore (using sem_post). Once woken up, it decrements the value and returns.

Key Concept: Atomicity Crucially, the “test and decrement” happens as a single, atomic step. The kernel guarantees that no two processes can see a value of 1 and both decrement it to 0 simultaneously.

2. The sem_trywait Function

This is the non-blocking version of the function.

#include <semaphore.h>
 
int sem_trywait(sem_t *sem);
// Returns: 0 if OK, -1 on error

How it works:

  1. Test: It checks the current value of the semaphore.
  2. Decrement or Fail:
    • If value > 0: It decrements the counter by 1 and returns 0 (Success).
    • If value == 0: It does not block. Instead, it returns -1 immediately and sets the error variable errno to EAGAIN.
3. When to use which?
  • Use sem_wait when your program absolutely cannot proceed without the resource (e.g., waiting for data to arrive in a buffer).
  • Use sem_trywait when your program has other work it can do if the resource isn’t ready (e.g., “Check if the printer is free; if not, I’ll update the display and try again later”).
Summary Table
FunctionSemaphore Value is > 0Semaphore Value is 0
sem_waitDecrements value, Returns 0.Blocks (sleeps) until value > 0.
sem_trywaitDecrements value, Returns 0.Returns -1 immediately (errno = EAGAIN).