C++0x has no semaphores? How to synchronize threads?
You can easily build one from a mutex and a condition variable:
#include <mutex>#include <condition_variable>class semaphore { std::mutex mutex_; std::condition_variable condition_; unsigned long count_ = 0; // Initialized as locked.public: void release() { std::lock_guard<decltype(mutex_)> lock(mutex_); ++count_; condition_.notify_one(); } void acquire() { std::unique_lock<decltype(mutex_)> lock(mutex_); while(!count_) // Handle spurious wake-ups. condition_.wait(lock); --count_; } bool try_acquire() { std::lock_guard<decltype(mutex_)> lock(mutex_); if(count_) { --count_; return true; } return false; }};
Based on Maxim Yegorushkin's answer, I tried to make the example in C++11 style.
#include <mutex>#include <condition_variable>class Semaphore {public: Semaphore (int count_ = 0) : count(count_) {} inline void notify() { std::unique_lock<std::mutex> lock(mtx); count++; cv.notify_one(); } inline void wait() { std::unique_lock<std::mutex> lock(mtx); while(count == 0){ cv.wait(lock); } count--; }private: std::mutex mtx; std::condition_variable cv; int count;};
I decided to write the most robust/generic C++11 semaphore I could, in the style of the standard as much as I could (note using semaphore = ...
, you normally would just use the name semaphore
similar to normally using string
not basic_string
):
template <typename Mutex, typename CondVar>class basic_semaphore {public: using native_handle_type = typename CondVar::native_handle_type; explicit basic_semaphore(size_t count = 0); basic_semaphore(const basic_semaphore&) = delete; basic_semaphore(basic_semaphore&&) = delete; basic_semaphore& operator=(const basic_semaphore&) = delete; basic_semaphore& operator=(basic_semaphore&&) = delete; void notify(); void wait(); bool try_wait(); template<class Rep, class Period> bool wait_for(const std::chrono::duration<Rep, Period>& d); template<class Clock, class Duration> bool wait_until(const std::chrono::time_point<Clock, Duration>& t); native_handle_type native_handle();private: Mutex mMutex; CondVar mCv; size_t mCount;};using semaphore = basic_semaphore<std::mutex, std::condition_variable>;template <typename Mutex, typename CondVar>basic_semaphore<Mutex, CondVar>::basic_semaphore(size_t count) : mCount{count}{}template <typename Mutex, typename CondVar>void basic_semaphore<Mutex, CondVar>::notify() { std::lock_guard<Mutex> lock{mMutex}; ++mCount; mCv.notify_one();}template <typename Mutex, typename CondVar>void basic_semaphore<Mutex, CondVar>::wait() { std::unique_lock<Mutex> lock{mMutex}; mCv.wait(lock, [&]{ return mCount > 0; }); --mCount;}template <typename Mutex, typename CondVar>bool basic_semaphore<Mutex, CondVar>::try_wait() { std::lock_guard<Mutex> lock{mMutex}; if (mCount > 0) { --mCount; return true; } return false;}template <typename Mutex, typename CondVar>template<class Rep, class Period>bool basic_semaphore<Mutex, CondVar>::wait_for(const std::chrono::duration<Rep, Period>& d) { std::unique_lock<Mutex> lock{mMutex}; auto finished = mCv.wait_for(lock, d, [&]{ return mCount > 0; }); if (finished) --mCount; return finished;}template <typename Mutex, typename CondVar>template<class Clock, class Duration>bool basic_semaphore<Mutex, CondVar>::wait_until(const std::chrono::time_point<Clock, Duration>& t) { std::unique_lock<Mutex> lock{mMutex}; auto finished = mCv.wait_until(lock, t, [&]{ return mCount > 0; }); if (finished) --mCount; return finished;}template <typename Mutex, typename CondVar>typename basic_semaphore<Mutex, CondVar>::native_handle_type basic_semaphore<Mutex, CondVar>::native_handle() { return mCv.native_handle();}