Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

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

like image 916
jonderry Avatar asked Oct 13 '10 23:10

jonderry


1 Answers

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_;
    }

};
like image 161
Doug Avatar answered Oct 13 '22 11:10

Doug