+++ title = "Semaphore" +++ # Semaphore A semaphore is another synchronization primitive. It is initialized to some value. Threads can either `sem_wait` or `sem_post` which lowers or increases the value. If the value reaches zero and a wait is called, the thread will be blocked until a post is called. Using a semaphore is as easy as using a mutex. First, decide if on the initial value, for example the number of remaining spaces in an array. Unlike pthread mutex there are no shortcuts to creating a semaphore - use `sem_init`. ```c #include sem_t s; int main() { sem_init(&s, 0, 10); // returns -1 (=FAILED) on OS X sem_wait(&s); // Could do this 10 times without blocking sem_post(&s); // Announce that we've finished (and one more resource item is available; increment count) sem_destroy(&s); // release resources of the semaphore } ``` When using a semaphore, wait and post can be called from different threads! Unlike a mutex, the increment and decrement can be from different threads. This becomes especially useful if you want to use a semaphore to implement a mutex. A mutex is a semaphore that always waits before it posts. Some textbooks will refer to a mutex as a binary semaphore. You do have to be careful to never add more than one to a semaphore or otherwise your mutex abstraction breaks. That is usually why a mutex is used to implement a semaphore and vice versa. - Initialize the semaphore with a count of one. - Replace `pthread_mutex_lock` with `sem_wait` - Replace `pthread_mutex_unlock` with `sem_post` ```c sem_t s; sem_init(&s, 0, 1); sem_wait(&s); // Critical Section sem_post(&s); ``` But be warned, it isn’t the same! A mutex can handle what we call lock inversion well. Meaning the following code breaks with a traditional mutex, but produces a race condition with threads. ```c // Thread 1 sem_wait(&s); // Critical Section sem_post(&s); // Thread 2 // Some threads want to see the world burn sem_post(&s); // Thread 3 sem_wait(&s); // Not thread-safe! sem_post(&s); ``` If we replace it with mutex lock, it won’t work now. ```c // Thread 1 mutex_lock(&s); // Critical Section mutex_unlock(&s); // Thread 2 // Foiled! mutex_unlock(&s); // Thread 3 mutex_lock(&s); // Now it's thread-safe mutex_unlock(&s); ``` Also, binary semaphores are different than mutexes because one thread can unlock a mutex from a different thread. ### Signal Safety Also, `sem_post` is one of a handful of functions that can be correctly used inside a signal handler `pthread_mutex_unlock` is not. We can release a waiting thread that can now make all of the calls that we disallowed to call inside the signal handler itself e.g. `printf`. Here is some code that utilizes this; ```c #include #include #include #include #include sem_t s; void handler(int signal) { sem_post(&s); /* Release the Kraken! */ } void *singsong(void *param) { sem_wait(&s); printf("Waiting until a signal releases...\n"); } int main() { int ok = sem_init(&s, 0, 0 /* Initial value of zero*/); if (ok == -1) { perror("Could not create unnamed semaphore"); return 1; } signal(SIGINT, handler); // Too simple! See Signals chapter pthread_t tid; pthread_create(&tid, NULL, singsong, NULL); pthread_exit(NULL); /* Process will exit when there are no more threads */ } ``` Other uses for semaphores are keeping track of empty spaces in arrays. We will discuss these in the thread-safe data structures section.