Semaphores
Semaphores are a common form of synchronization that allows threads to post
and
wait
on a semaphore to control when threads wake or sleep.
Semaphores differ from other synchronization primitives in that they are async safe
and
can be manipulated by signal handlers. If the desired effect is to have a signal handler wake a
thread, semaphores are the right choice.
The QNX OS implementation of semaphores supports both named and unnamed semaphores
(see Named and unnamed semaphores
below).
Semaphore or mutex?
A key advantage of semaphores over mutexes is that semaphores are defined to operate between processes.
Although our mutexes work between processes, the POSIX thread standard considers this an optional capability. Thus, if your code will rely on mutexes working between processes, to ensure portability you should probably use semaphores rather than mutexes.
However, depending on your needs you may wish to use mutexes rather than semaphores after considering the following:
- In general, mutexes are much faster than semaphores, which always require a kernel entry.
- For synchronization between threads in a single process, mutexes are more efficient than semaphores.
- Semaphores don't affect a thread's effective priority; if you need priority inheritance, use a
mutex (see
Mutexes: mutual exclusion locks
in this chapter).
Using semaphores
The post (sem_post()) operation increments the semaphore; the wait (sem_wait()) operation decrements it.
If you wait on a semaphore that is positive, you will not block. Waiting on a nonpositive semaphore will block until some other thread executes a post. It is valid to post one or more times before a wait. This use allows one or more threads to execute the wait without blocking.
while (sem_wait(&s) && (errno == EINTR)) { do_nothing(); }
do_critical_region(); /* Semaphore was decremented */
For a complete list of functions you can use with semaphores, see the sem_*() functions in the C Library Reference.
Named and unnamed semaphores
Unnamed semaphores are created with sem_init(), and destroyed with sem_destroy(). They can be used by multiple threads within the same process. However, to use an unnamed semaphore between processes requires a shared memory object, which implies a large memory overhead.
Named semaphores are created with sem_open(), and closed with sem_close(). Like unnamed semaphores, they can be be used by multiple threads within the same process. Unlike unnamed semaphores, however, named semaphores can be easily shared between threads in different processes.
With the exception of anonymous named semaphores, named semaphores have a path and a name, so they can be found between processes without the use of shared memory objects and the overhead they imply. Named semaphores are therefore more useful for inter-process communication than are unnamed semaphores.
Additionally, named semaphores (including anonymous named semaphores) can be posted by a sigevent (e.g., attached to an IRQ or delivered by a server), and can be shared between a parent and a child process across a fork() without requiring a shared mapping.
Anonymous named semaphores don't have a path and name like other named semaphores, but they share the other advantages noted above. For more information about anonymous named semaphores, see sem_open() in the C Library Reference.