Skip to main content
Engineering LibreTexts

11.1: POSIX Semaphores

  • Page ID
    40641
  • \( \newcommand{\vecs}[1]{\overset { \scriptstyle \rightharpoonup} {\mathbf{#1}} } \) \( \newcommand{\vecd}[1]{\overset{-\!-\!\rightharpoonup}{\vphantom{a}\smash {#1}}} \)\(\newcommand{\id}{\mathrm{id}}\) \( \newcommand{\Span}{\mathrm{span}}\) \( \newcommand{\kernel}{\mathrm{null}\,}\) \( \newcommand{\range}{\mathrm{range}\,}\) \( \newcommand{\RealPart}{\mathrm{Re}}\) \( \newcommand{\ImaginaryPart}{\mathrm{Im}}\) \( \newcommand{\Argument}{\mathrm{Arg}}\) \( \newcommand{\norm}[1]{\| #1 \|}\) \( \newcommand{\inner}[2]{\langle #1, #2 \rangle}\) \( \newcommand{\Span}{\mathrm{span}}\) \(\newcommand{\id}{\mathrm{id}}\) \( \newcommand{\Span}{\mathrm{span}}\) \( \newcommand{\kernel}{\mathrm{null}\,}\) \( \newcommand{\range}{\mathrm{range}\,}\) \( \newcommand{\RealPart}{\mathrm{Re}}\) \( \newcommand{\ImaginaryPart}{\mathrm{Im}}\) \( \newcommand{\Argument}{\mathrm{Arg}}\) \( \newcommand{\norm}[1]{\| #1 \|}\) \( \newcommand{\inner}[2]{\langle #1, #2 \rangle}\) \( \newcommand{\Span}{\mathrm{span}}\)\(\newcommand{\AA}{\unicode[.8,0]{x212B}}\)

    A semaphore is a data structure used to help threads work together without interfering with each other.

    The POSIX standard specifies an interface for semaphores; it is not part of Pthreads, but most UNIXes that implement Pthreads also provide semaphores.

    POSIX semaphores have type sem_t. As usual, I put a wrapper around sem_t to make it easier to use. The interface is defined in sem.h:

    typedef sem_t Semaphore;
    
    Semaphore *make_semaphore(int value);
    void semaphore_wait(Semaphore *sem);
    void semaphore_signal(Semaphore *sem);
    

    Semaphore is a synonym for sem_t, but I find it more readable, and the capital letter reminds me to treat it like an object and pass it by pointer.

    The implementation of these functions is in sem.c:

    Semaphore *make_semaphore(int value)
    {
        Semaphore *sem = check_malloc(sizeof(Semaphore));
        int n = sem_init(sem, 0, value);
        if (n != 0) perror_exit("sem_init failed");
        return sem;
    }
    

    make_semaphore takes the initial value of the semaphore as a parameter. It allocates space for a Semaphore, initializes it, and returns a pointer to Semaphore.

    sem_init returns 0 if it succeeds and -1 if anything goes wrong. One nice thing about using wrapper functions is that you can encapsulate the error-checking code, which makes the code that uses these functions more readable.

    Here is the implementation of semaphore_wait:

    void semaphore_wait(Semaphore *sem)
    {
        int n = sem_wait(sem);
        if (n != 0) perror_exit("sem_wait failed");
    }
    

    And here is semaphore_signal:

    void semaphore_signal(Semaphore *sem)
    {
        int n = sem_post(sem);
        if (n != 0) perror_exit("sem_post failed");
    }
    

    I prefer to call this operation “signal” rather than “post”, although both terms are common.

    Here’s an example that shows how to use a semaphore as a mutex:

    Semaphore *mutex = make_semaphore(1);
    
    semaphore_wait(mutex);
      // protected code goes here
    semaphore_signal(mutex);
    

    When you use a semaphore as a mutex, you usually initialize it to 1 to indicate that the mutex is unlocked; that is, one thread can pass the semaphore without blocking.

    Here I am using the variable name mutex to indicate that the semaphore is being used as a mutex. But remember that the behavior of a semaphore is not the same as a Pthread mutex.


    This page titled 11.1: POSIX Semaphores is shared under a CC BY-NC license and was authored, remixed, and/or curated by Allen B. Downey (Green Tea Press) .

    • Was this article helpful?