POSIX Semaphores
POSIX Semaphores provide synchronization mechanisms that allow multiple processes or threads to coordinate access to shared resources safely. Unlike message queues, semaphores do not transfer data. Instead, they synchronize execution by controlling access through an integer counter managed by the kernel.
Learning Objectives
- Understand semaphore fundamentals.
- Learn binary and counting semaphores.
- Understand named and unnamed semaphores.
- Study the semaphore lifecycle.
- Prepare for synchronization APIs.
1. What is a Semaphore?
A semaphore is a synchronization object that controls access to shared resources. It maintains an internal counter. Processes or threads decrement the counter before entering a protected section and increment it after leaving. If the counter reaches zero, additional requests must wait until another execution context releases the semaphore.
2. Why are Semaphores Needed?
| Problem | Semaphore Solution |
|---|---|
| Race Conditions | Ensures exclusive access. |
| Shared Memory Access | Coordinates multiple processes. |
| Thread Synchronization | Controls execution order. |
| Limited Resources | Restricts concurrent access. |
| Producer–Consumer | Coordinates producers and consumers. |
3. Semaphore Concept
4. Binary Semaphore
A binary semaphore has only two logical states:
| Value | Meaning |
|---|---|
| 1 | Resource Available |
| 0 | Resource Busy |
Binary semaphores are commonly used to provide mutual exclusion for a single shared resource.
5. Counting Semaphore
A counting semaphore allows multiple concurrent users. The counter represents the number of available resource instances.
| Initial Count | Meaning |
|---|---|
| 5 | Five resources available. |
| 2 | Two resources remaining. |
| 0 | No resources available. |
6. Binary vs Counting Semaphore
| Feature | Binary | Counting |
|---|---|---|
| Maximum Value | 1 | Many |
| Purpose | Mutual Exclusion | Resource Management |
| Typical Usage | Single Resource | Resource Pool |
7. Named vs Unnamed Semaphores
| Named Semaphore | Unnamed Semaphore |
|---|---|
| Accessible by name. | Stored directly in shared memory. |
| Uses sem_open(). | Uses sem_init(). |
| Supports unrelated processes. | Supports threads or related processes sharing memory. |
| Requires sem_unlink(). | Requires sem_destroy(). |
8. Semaphore Data Type (sem_t)
POSIX semaphores are represented using the opaque
sem_t data type.
Applications treat sem_t as an abstract object
and manipulate it only through the POSIX semaphore APIs.
9. Linux Implementation
On Linux, named POSIX semaphores are typically implemented
using the /dev/shm shared memory filesystem.
Semaphore objects often appear with names beginning with
sem.
The exact implementation is Linux-specific; applications should use only the POSIX APIs and not depend on filesystem details.
10. Interview Questions
- What is a semaphore?
- Why are semaphores used?
- How does a semaphore differ from a mutex?
- What is the difference between binary and counting semaphores?
- When should you use a counting semaphore?
- What is a named semaphore?
- What is an unnamed semaphore?
- Which type is represented by
sem_t? - Where are named semaphores commonly implemented on Linux?
- Can semaphores transfer application data?
11. sem_open()
The sem_open() function creates a new named semaphore
or opens an existing one.
Named semaphores allow unrelated processes to synchronize by
opening the same semaphore name.
12. sem_open() Parameters
| Parameter | Description |
|---|---|
name |
Semaphore name beginning with '/'. |
oflag |
Creation and access flags. |
mode |
Permission bits (used with O_CREAT). |
value |
Initial semaphore count. |
13. Semaphore Creation Flags
| Flag | Description |
|---|---|
O_CREAT |
Create semaphore if it does not exist. |
O_EXCL |
Fail if semaphore already exists. |
When O_CREAT and O_EXCL are used together,
creation succeeds only if the semaphore name does not already exist.
14. sem_close()
The sem_close() function closes a named semaphore
descriptor previously returned by sem_open().
Closing the semaphore releases the calling process's reference but
does not remove the semaphore from the system.
15. sem_unlink()
The sem_unlink() function removes the name associated
with a named semaphore.
The semaphore object remains available until every process has
closed its reference.
16. sem_init()
The sem_init() function initializes an unnamed semaphore.
Unnamed semaphores are typically used for threads or related
processes that share memory.
| Parameter | Description |
|---|---|
sem |
Semaphore object. |
pshared |
0 = Threads, Non-zero = Shared Processes. |
value |
Initial semaphore count. |
17. sem_destroy()
The sem_destroy() function destroys an unnamed semaphore
that was initialized using sem_init().
It must not be used for named semaphores.
18. Permission Bits
| Permission | Description |
|---|---|
| 0400 | Owner Read |
| 0200 | Owner Write |
| 0040 | Group Read |
| 0020 | Group Write |
| 0004 | Others Read |
| 0002 | Others Write |
19. Example: Creating a Named Semaphore
20. Linux Commands
| Command | Description |
|---|---|
ls /dev/shm |
Display named semaphore objects. |
mount | grep shm |
Verify tmpfs mount. |
man sem_open |
Semaphore creation manual. |
man sem_init |
Unnamed semaphore manual. |
man sem_destroy |
Semaphore cleanup manual. |
21. Interview Questions
- What is the difference between
sem_open()andsem_init()? - When should a named semaphore be used?
- When should an unnamed semaphore be used?
- Why is
psharedneeded? - What does
SEM_FAILEDindicate? - What is the purpose of
sem_close()? - Why is
sem_unlink()required? - Why must
sem_destroy()not be used on named semaphores? - What is the effect of
O_EXCL? - What permissions are assigned during semaphore creation?
22. sem_wait()
The sem_wait() function attempts to decrement
(acquire) the semaphore.
If the semaphore value is greater than zero, it is decremented
immediately.
If the semaphore value is zero, the calling thread or process
blocks until another execution context releases the semaphore.
23. sem_trywait()
The sem_trywait() function performs the same operation
as sem_wait(), but never blocks.
If the semaphore cannot be acquired immediately,
the function returns an error.
| Condition | Result |
|---|---|
| Semaphore Available | Acquire Immediately |
| Semaphore Unavailable | Returns -1 (errno = EAGAIN) |
24. sem_timedwait()
The sem_timedwait() function waits until either:
- The semaphore becomes available, or
- The specified timeout expires.
If the timeout expires before the semaphore becomes available,
the function returns -1 and sets
errno to ETIMEDOUT.
25. sem_post()
The sem_post() function increments
(releases) a semaphore.
If one or more execution contexts are blocked in
sem_wait(), the kernel wakes one of them.
26. sem_getvalue()
The sem_getvalue() function retrieves the current
semaphore value.
The returned value should be used only for monitoring or debugging. Applications should not rely on it for synchronization because the value may change immediately after it is read.
27. Semaphore State Transition
28. Example: Binary Semaphore
Only one execution context can enter the critical section at a time.
29. Producer–Consumer Synchronization
Semaphores coordinate access to the shared buffer while preventing overflow and underflow.
30. Linux Debugging Commands
| Command | Description |
|---|---|
man sem_wait |
Semaphore wait documentation. |
man sem_post |
Semaphore release documentation. |
man sem_trywait |
Non-blocking wait documentation. |
man sem_timedwait |
Timed wait documentation. |
man sem_getvalue |
Retrieve semaphore value. |
31. Advanced Interview Questions
- What is the difference between
sem_wait()andsem_trywait()? - When should
sem_timedwait()be used? - What error is returned by
sem_trywait()if the semaphore is unavailable? - What happens when
sem_post()is called? - Can multiple waiting threads be awakened by one
sem_post()? - Why is
sem_getvalue()unsuitable for synchronization decisions? - How does a binary semaphore protect a critical section?
- How do semaphores solve the Producer–Consumer problem?
- What happens if
sem_wait()is called when the semaphore value is zero? - What timeout error is returned by
sem_timedwait()?
32. Semaphore Lifecycle
For unnamed semaphores, the lifecycle differs:
33. Named vs Unnamed Semaphore Comparison
| Feature | Named Semaphore | Unnamed Semaphore |
|---|---|---|
| Creation | sem_open() | sem_init() |
| Removal | sem_unlink() | sem_destroy() |
| Visibility | System-wide by name | Shared memory only |
| Used By | Unrelated Processes | Threads / Related Processes |
| Storage | Kernel-managed object | Application memory |
34. Common Programming Mistakes
- Calling
sem_wait()without a matchingsem_post(). - Destroying a semaphore while another thread is still using it.
- Using
sem_destroy()on a named semaphore. - Forgetting to call
sem_unlink()for named semaphores. - Acquiring multiple semaphores in inconsistent order.
- Ignoring API return values.
- Sharing an unnamed semaphore without shared memory.
35. Deadlock Prevention
Semaphores themselves do not prevent deadlocks. Applications must follow consistent locking strategies.
| Recommendation | Reason |
|---|---|
| Acquire semaphores in a fixed order. | Prevents circular waiting. |
| Release semaphores promptly. | Reduces blocking time. |
| Avoid unnecessary nested locks. | Reduces deadlock risk. |
| Use timed waits where appropriate. | Helps detect stalled synchronization. |
36. Best Practices
- Always pair every
sem_wait()withsem_post(). - Use named semaphores only when unrelated processes must synchronize.
- Prefer unnamed semaphores for thread synchronization.
- Always check API return values.
- Destroy or unlink semaphores during application shutdown.
- Keep critical sections as short as possible.
- Document semaphore ownership and acquisition order.
37. Debugging Tips
| Problem | Possible Cause |
|---|---|
| Program never continues | Semaphore never released. |
| sem_wait() blocks forever | No matching sem_post(). |
| SEM_FAILED | sem_open() creation/open failed. |
| EINVAL | Invalid semaphore object or parameters. |
| Semaphore remains after exit | sem_unlink() was omitted. |
38. Advanced Interview Questions
- Explain the lifecycle of a named semaphore.
- Explain the lifecycle of an unnamed semaphore.
- Why are unnamed semaphores generally preferred for threads?
- What happens if
sem_post()is forgotten? - How can semaphore misuse cause deadlocks?
- Why should semaphores always be acquired in a fixed order?
- When should
sem_timedwait()be preferred? - Can multiple threads wait on the same semaphore?
- How does a semaphore differ from a mutex regarding resource counting?
- Why should
sem_getvalue()not be used for synchronization logic?
39. Module Summary
In this module, we studied POSIX Semaphores in detail.
We covered semaphore fundamentals, binary and counting semaphores,
named and unnamed semaphores, semaphore creation APIs
(sem_open() and sem_init()),
synchronization operations
(sem_wait(),
sem_trywait(),
sem_timedwait(),
sem_post()),
resource cleanup APIs
(sem_close(),
sem_unlink(),
sem_destroy()),
deadlock prevention techniques, debugging strategies, and
recommended programming practices.
POSIX semaphores provide efficient synchronization for both
multi-threaded applications and cooperating processes.
Concept Mastery Assessment — Module 45
Verify your conceptual understanding with 12 targeted technical assessment questions. Instant feedback and explanations are provided for every choice.