How can I achieve something similar to a semaphore using boost in c++?

17,047

This is one way of implementing a very simple semaphore using Boost.Thread. It's an inter-thread semaphore, not an interprocess one. No warranties implied, etc. - I haven't even compiled the code. It illustrates how mutexes and condition variables interact, and assumes a reasonably recent version of Boost.

Notice how the mutex and condition variable are "paired" - threads must have a lock to the mutex to wait on the condition variable, and re-acquire the lock when they're woken up. Also, the code that changes the data needs to explicitly wake up other code that might be waiting. This means that the mutex, condition variable, data, and the condition(s) that cause the wakeup, are all closely coupled. The tight coupling also means that the data, mutex, and condition variable should be encapsulated if possible - any external modification can break the code in strange ways, including deadlocks, missed wakeups, and other strange bugs.

All this is really meant as a complement to Vlad Lazarenko's answer - understanding the theory and principles are at least as important as having "working" code, in multi-threaded programming.

#include <boost/thread/condition_variable.hpp>
#include <boost/thread/mutex.hpp>    
#include <boost/thread/lock_types.hpp>


class semaphore
{
    //The current semaphore count.
    unsigned int count_;

    //mutex_ protects count_.
    //Any code that reads or writes the count_ data must hold a lock on
    //the mutex.
    boost::mutex mutex_;

    //Code that increments count_ must notify the condition variable.
    boost::condition_variable condition_;

public:
    explicit semaphore(unsigned int initial_count) 
       : count_(initial_count),
         mutex_(), 
         condition_()
    {
    }

    unsigned int get_count() //for debugging/testing only
    {
        //The "lock" object locks the mutex when it's constructed,
        //and unlocks it when it's destroyed.
        boost::unique_lock<boost::mutex> lock(mutex_);
        return count_;
    }

    void signal() //called "release" in Java
    {
        boost::unique_lock<boost::mutex> lock(mutex_);

        ++count_;

        //Wake up any waiting threads. 
        //Always do this, even if count_ wasn't 0 on entry. 
        //Otherwise, we might not wake up enough waiting threads if we 
        //get a number of signal() calls in a row.
        condition_.notify_one(); 
    }

    void wait() //called "acquire" in Java
    {
        boost::unique_lock<boost::mutex> lock(mutex_);
        while (count_ == 0)
        {
             condition_.wait(lock);
        }
        --count_;
    }

};
Share:
17,047
jonderry
Author by

jonderry

Updated on July 27, 2022

Comments

  • jonderry
    jonderry almost 2 years

    I noticed that boost does not seem to support semaphores. What's the easiest way to achieve a similar effect?

  • Keyur Padalia
    Keyur Padalia over 12 years
    Works like a charm. Too bad this is no longer part of Boost itself.
  • daramarak
    daramarak over 12 years
    + 1 for the code. Are there any point to the mutex in get count? The count will be "old" when received anyway, won't it?
  • Jon Watte
    Jon Watte over 11 years
    Correct, the count will be old when returned. Getting the count of a semaphore for reasons other than debugging is likely a bug in your program.
  • MistyD
    MistyD over 9 years
    Dough could you please use this in an example. I am confused on how to use it and how it allows access to multiple threads at a time