Although mutexes and condition variables provide an ideal solution to most synchronization needs, they cannot meet all needs. One example of this is a need to communicate between a POSIX signal-catching function and a thread waiting for some asynchronous event. In new code, it is best to use sigwait or sigwaitinfo rather than relying on a signal-catching function, and this neatly avoids this problem. However, the use of asynchronous POSIX signal-catching functions is well established and widespread, and most programmers working with threads and existing code will probably encounter this situation.
To awaken a thread from a POSIX signal-catching function, you need a mechanism that's reentrant with respect to POSIX signals (async-signal safe). POSIX provides relatively few of these functions, and none of the Pthreads functions is included. That's primarily because an async-signal safe mutex lock operation would be many times slower than one that isn't async-signal safe. Outside of the kernel, making a function async-signal safe usually requires that the function mask (block) signals while it runs — and that is expensive.
In case you're curious, here is the full list of POSIX 1003.1-1996 functions that are async-signal safe (some of these functions exist only when certain POSIX options are defined, such as _POSIX_ASYNCHRONOUS_IO or _POSIX_TIMERS):
access | getoverrun | sigismember |
aio_error | getgroups | sigpending |
aio_return | getpgrp | sigprocmask |
aio_suspend | getpid | sigqueue |
alarm | getppid | sigsuspend |
cfgetispeed | getuid | sleep |
cfgetospeed | kill | stat |
cfsetispeed | link | sysconf |
cfsetospeed | lseek | tcdrain |
chdir | mkdir | tcflow |
chmod | mkfifo | tcflush |
chown | open | tcgetattr |
clock_gettime | pathconf | tcgetpgrp |
close | pause | tcsendbreak |
creat | pipe | tcsetattr |
dup2 | read | tcsetpgrp |
dup | rename | time |
execle | rmdir | timer_getoverrun |
execve | sem_post | timer_gettime |
_exit | setgid | timer_settime |
fcntl | setpgid | times |
fdatasync | setsid | umask |
fork | setuid | uname |
fstat | sigaction | unlink |
fsync | sigaddset | utime |
getegid | sigdelset | wait |
geteuid | sigemptyset | waitpid |
getgid | sigfillset | write |
POSIX.1b provides counting semaphores, and most systems that support Pthreads also support POSIX.1b semaphores. You may notice that the sem_post function, which wakes threads waiting on a semaphore, appears in the list of async-signal safe functions. If your system supports POSIX semaphores (
A semaphore is a different kind of synchronization object — it is a little like a mutex, a little like a condition variable. The differences can make semaphores a little harder to use for many common tasks, but they make semaphores substantially easier to use for certain specialized purposes. In particular, semaphores can be
Semaphores are a general synchronization mechanism. We just have no reason to use them that way.
I am emphasizing the use of semaphores to pass information from a signal-catching function, rather than for general use, for a couple of reasons. One reason is that semaphores are part of a different standard. As I said, most systems that support Pthreads will also support POSIX. lb, but there is no such requirement anywhere in the standard. So you may well find yourself without access to semaphores, and you shouldn't feel dependent on them. {Of course, you may also find yourself
Another reason for keeping semaphores here with signals is that, although semaphores are a completely general synchronization mechanism, it can be more difficult to solve many problems using semaphores—mutexes and condition variables are simpler. If you've got Pthreads, you only