POSIX Semaphores

 

POSIX Semaphores
Chapter 53 — Linux System Programming (TLPI)
5
Tutorial Files
Ch.53
TLPI Chapter
IPC
Topic Area

What are POSIX Semaphores?

A semaphore is a kernel-maintained integer whose value is never allowed to fall below zero. It is used to control access to shared resources among multiple processes or threads. POSIX semaphores are the modern, simpler alternative to the older System V semaphore API.

Think of a semaphore like a token counter at a parking lot. If tokens are available (value > 0), a car can enter (decrement). When the lot is full (value = 0), cars wait. When a car leaves, it returns the token (increment).

POSIX provides two types of semaphores — Named and Unnamed. Both use the same underlying operations but differ in how they are created and shared.

Key Terms in This Chapter

sem_t sem_open() sem_close() sem_unlink() sem_wait() sem_post() sem_trywait() sem_timedwait() sem_getvalue() sem_init() sem_destroy() Named Semaphore Unnamed Semaphore Binary Semaphore Counting Semaphore SEM_NSEMS_MAX SEM_VALUE_MAX

Named vs Unnamed Semaphores

The table below summarizes the two types of POSIX semaphores side by side.

Property Named Semaphore Unnamed Semaphore
How created sem_open() with a name like /mysem sem_init() on a sem_t variable
Identified by A filesystem-like name (string) A memory address (pointer)
Sharing Any process knowing the name Threads in same process OR processes sharing memory
Persistent Yes, until sem_unlink() called Exists only as long as memory lives
Cleanup sem_close() + sem_unlink() sem_destroy()
Use case Cross-process synchronization Thread sync or process sync via shared memory

How Semaphore Operations Work

A semaphore holds a non-negative integer value. Two fundamental operations exist:

sem_wait() — P operation / Decrement

If semaphore value > 0, decrement it and return immediately. If value == 0, block (sleep) until another thread/process increments it. Also called “down”, “acquire”, or “lock”.

sem_post() — V operation / Increment

Always increments the semaphore value by 1. If any process/thread was blocked waiting, one is woken up. Also called “up”, “release”, or “signal”. This operation never blocks.

Semaphore State Transitions
Value = 2
2 permits free
sem_wait()
Value = 1
1 permit free
sem_wait()
Value = 0
BLOCKS next waiter
sem_post()
Value = 1
Waiter woken up

Binary Semaphore vs Counting Semaphore
Binary Semaphore (Mutex-like)

Value is either 0 or 1. Used like a mutex to protect a critical section. Initialized to 1. One thread/process “acquires” it (sets to 0), does work, then “releases” it (sets to 1).

Counting Semaphore

Value can be any non-negative integer. Used to control access to a pool of resources (e.g., 5 database connections). Initialized to N = number of available resources.

Quick Code Example: Binary Semaphore Protecting a Critical Section

Below is a minimal example showing the concept of protecting shared data using a POSIX semaphore. Detailed examples are in the Named and Unnamed tutorial files.

#include <semaphore.h>
#include <stdio.h>
#include <stdlib.h>

/*
 * Conceptual example: binary semaphore as mutex
 * sem initialized to 1 = "unlocked"
 * sem_wait() = acquire lock (value 1 -> 0)
 * sem_post() = release lock (value 0 -> 1)
 */

sem_t sem;
int shared_counter = 0;

void safe_increment(void) {
    /* Acquire: blocks if another thread holds the lock */
    if (sem_wait(&sem) == -1) {
        perror("sem_wait");
        exit(EXIT_FAILURE);
    }

    /* --- Critical Section --- */
    shared_counter++;
    printf("Counter: %d\n", shared_counter);
    /* --- End Critical Section --- */

    /* Release: allow other threads to proceed */
    if (sem_post(&sem) == -1) {
        perror("sem_post");
        exit(EXIT_FAILURE);
    }
}

int main(void) {
    /* Initialize unnamed semaphore: thread-shared, initial value = 1 */
    if (sem_init(&sem, 0, 1) == -1) {
        perror("sem_init");
        exit(EXIT_FAILURE);
    }

    safe_increment();
    safe_increment();

    sem_destroy(&sem);
    return 0;
}

Compile: gcc -o sem_basic sem_basic.c -lpthread — Always link with -lpthread (or -lrt on older systems) when using POSIX semaphores.

Chapter 53 Tutorial Series — Navigation
File 1 (This file): Overview, Named vs Unnamed, sem_wait/sem_post concepts
File 2: Named Semaphores — sem_open, sem_close, sem_unlink, sem_wait, sem_post, sem_trywait, sem_timedwait, sem_getvalue with full examples
File 3: Unnamed Semaphores — sem_init, sem_destroy, thread-sharing, process-sharing, full example
File 4: Comparisons — POSIX vs SysV semaphores, POSIX semaphores vs Pthreads mutexes
File 5: Limits and Summary — SEM_NSEMS_MAX, SEM_VALUE_MAX, complete interview Q&A

Interview Questions — POSIX Semaphore Basics
Q1. What is a semaphore and how is it different from a mutex?

A semaphore is a kernel-maintained integer used for synchronization. It can have values > 1 (counting semaphore), allowing it to control access to a pool of resources. A mutex is strictly binary (locked/unlocked) and has ownership — only the thread that locked it can unlock it. A semaphore has no ownership; any thread/process can post it.

Q2. What are the two types of POSIX semaphores?

Named semaphores are identified by a string name (like /mysem) and can be shared between unrelated processes. Unnamed semaphores reside in memory (a sem_t variable) and are shared either between threads of the same process or between related processes via shared memory.

Q3. Can a semaphore value go negative?

No. The semaphore value is always ≥ 0. When a process calls sem_wait() on a zero-valued semaphore, it blocks instead of making the value negative. This blocking behavior is what makes semaphores useful for synchronization.

Q4. What header file is needed for POSIX semaphores?

<semaphore.h> is required. When compiling, you must also link with -lpthread. On older Linux systems, you may also need -lrt for real-time extensions.

Q5. What is the difference between P and V operations on a semaphore?

P (proberen / wait / down): Tries to decrement the semaphore. Blocks if value is 0. Corresponds to sem_wait(). V (verhogen / post / up): Increments the semaphore. Wakes a waiting process if any. Corresponds to sem_post(). These Dutch terms come from Dijkstra who invented semaphores.

Start Learning POSIX Semaphores

Continue to the next file to learn Named Semaphores in depth.

Next: Named Semaphores →

Leave a Reply

Your email address will not be published. Required fields are marked *