]> git.sesse.net Git - casparcg/blobdiff - common/semaphore.h
[ffmpeg] Removed unused code path
[casparcg] / common / semaphore.h
index bd3c6d7ecea49b10b4853133945aa18f8a893a83..04e36426045c48c9603807a9c7f0a90d1806c9f8 100644 (file)
@@ -25,7 +25,7 @@
 
 #include <boost/noncopyable.hpp>
 #include <boost/thread/mutex.hpp>
-#include <boost/thread/condition.hpp>
+#include <boost/thread/condition_variable.hpp>
 
 namespace caspar {
 
@@ -45,14 +45,14 @@ class semaphore : boost::noncopyable
 {
        mutable boost::mutex mutex_;
        unsigned int permits_;
-       boost::condition_variable permits_available_;
+       boost::condition_variable_any permits_available_;
 public:
        /**
         * Constructor.
         *
         * @param permits The initial number of permits.
         */
-       semaphore(unsigned int permits)
+       explicit semaphore(unsigned int permits)
                : permits_(permits)
        {
        }
@@ -62,7 +62,7 @@ public:
         */
        void release()
        {
-               boost::mutex::scoped_lock lock(mutex_);
+               boost::unique_lock<boost::mutex> lock(mutex_);
 
                ++permits_;
 
@@ -76,7 +76,7 @@ public:
         */
        void release(unsigned int permits)
        {
-               boost::mutex::scoped_lock lock(mutex_);
+               boost::unique_lock<boost::mutex> lock(mutex_);
 
                permits_ += permits;
 
@@ -89,7 +89,7 @@ public:
         */
        void acquire()
        {
-               boost::mutex::scoped_lock lock(mutex_);
+               boost::unique_lock<boost::mutex> lock(mutex_);
 
                while (permits_ == 0u)
                {
@@ -107,19 +107,60 @@ public:
         */
        void acquire(unsigned int permits)
        {
-               boost::mutex::scoped_lock lock(mutex_);
+               boost::unique_lock<boost::mutex> lock(mutex_);
                auto num_acquired = 0u;
 
-               while (permits_ == 0u && num_acquired < permits)
+               while (true)
                {
+                       auto num_wanted = permits - num_acquired;
+                       auto to_drain = std::min(num_wanted, permits_);
+
+                       permits_ -= to_drain;
+                       num_acquired += to_drain;
+
+                       if (num_acquired == permits)
+                               break;
+
                        permits_available_.wait(lock);
+               }
+       }
+
+       /**
+        * Acquire a number of permits. Will block until the given number of
+        * permits has been acquired if not enough permits are currently available
+        * or the timeout has passed.
+        *
+        * @param permits The number of permits to acquire.
+        * @param timeout The timeout (will be used for each permit).
+        *
+        * @return whether successfully acquired within timeout or not.
+        */
+       template <typename Rep, typename Period>
+       bool try_acquire(unsigned int permits, const boost::chrono::duration<Rep, Period>& timeout)
+       {
+               boost::unique_lock<boost::mutex> lock(mutex_);
+               auto num_acquired = 0u;
 
+               while (true)
+               {
                        auto num_wanted = permits - num_acquired;
                        auto to_drain = std::min(num_wanted, permits_);
 
                        permits_ -= to_drain;
                        num_acquired += to_drain;
+
+                       if (num_acquired == permits)
+                               break;
+
+                       if (permits_available_.wait_for(lock, timeout) == boost::cv_status::timeout)
+                       {
+                               lock.unlock();
+                               release(num_acquired);
+                               return false;
+                       }
                }
+
+               return true;
        }
 
        /**
@@ -131,7 +172,7 @@ public:
         */
        bool try_acquire()
        {
-               boost::mutex::scoped_lock lock(mutex_);
+               boost::unique_lock<boost::mutex> lock(mutex_);
 
                if (permits_ == 0u)
                        return false;
@@ -149,10 +190,50 @@ public:
         */
        unsigned int permits() const
        {
-               boost::mutex::scoped_lock lock(mutex_);
+               boost::unique_lock<boost::mutex> lock(mutex_);
 
                return permits_;
        }
 };
 
+/**
+ * Enables RAII-style acquire/release on scope exit unless committed.
+ */
+class acquire_transaction : boost::noncopyable
+{
+       semaphore& semaphore_;
+       bool committed_;
+public:
+       /**
+        * Constructor.
+        *
+        * @param semaphore        The semaphore to acquire one permit from.
+        * @param already_acquired Whether a permit has already been acquired or not.
+        */
+       acquire_transaction(semaphore& semaphore, bool already_acquired = false)
+               : semaphore_(semaphore)
+               , committed_(false)
+       {
+               if (!already_acquired)
+                       semaphore_.acquire();
+       }
+
+       /**
+        * Destructor that will release one permit if commit() has not been called.
+        */
+       ~acquire_transaction()
+       {
+               if (!committed_)
+                       semaphore_.release();
+       }
+
+       /**
+        * Ensure that the acquired permit is kept on destruction.
+        */
+       void commit()
+       {
+               committed_ = true;
+       }
+};
+
 }