2 * Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>
4 * This file is part of CasparCG (www.casparcg.com).
6 * CasparCG is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation, either version 3 of the License, or
9 * (at your option) any later version.
11 * CasparCG is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with CasparCG. If not, see <http://www.gnu.org/licenses/>.
19 * Author: Helge Norberg, helge.norberg@svt.se
26 #include <boost/noncopyable.hpp>
27 #include <boost/thread/mutex.hpp>
28 #include <boost/thread/condition_variable.hpp>
32 template <class N, class Func>
33 void repeat_n(N times_to_repeat_block, const Func& func)
35 for (N i = 0; i < times_to_repeat_block; ++i)
42 * Counting semaphore modelled after java.util.concurrent.Semaphore
44 class semaphore : boost::noncopyable
46 mutable boost::mutex mutex_;
47 unsigned int permits_;
48 boost::condition_variable_any permits_available_;
53 * @param permits The initial number of permits.
55 explicit semaphore(unsigned int permits)
65 boost::unique_lock<boost::mutex> lock(mutex_);
69 permits_available_.notify_one();
75 * @param permits The number of permits to release.
77 void release(unsigned int permits)
79 boost::unique_lock<boost::mutex> lock(mutex_);
83 repeat_n(permits, [this] { permits_available_.notify_one(); });
87 * Acquire a permit. Will block until one becomes available if no permit is
88 * currently available.
92 boost::unique_lock<boost::mutex> lock(mutex_);
94 while (permits_ == 0u)
96 permits_available_.wait(lock);
103 * Acquire a number of permits. Will block until the given number of
104 * permits has been acquired if not enough permits are currently available.
106 * @param permits The number of permits to acquire.
108 void acquire(unsigned int permits)
110 boost::unique_lock<boost::mutex> lock(mutex_);
111 auto num_acquired = 0u;
115 auto num_wanted = permits - num_acquired;
116 auto to_drain = std::min(num_wanted, permits_);
118 permits_ -= to_drain;
119 num_acquired += to_drain;
121 if (num_acquired == permits)
124 permits_available_.wait(lock);
129 * Acquire one permits if permits are currently available. Does not block
130 * until one is available, but returns immediately if unavailable.
132 * @return true if a permit was acquired or false if no permits where
133 * currently available.
137 boost::unique_lock<boost::mutex> lock(mutex_);
150 * @return the current number of permits (may have changed at the time of
153 unsigned int permits() const
155 boost::unique_lock<boost::mutex> lock(mutex_);
162 * Enables RAII-style acquire/release on scope exit unless committed.
164 class acquire_transaction : boost::noncopyable
166 semaphore& semaphore_;
172 * @param semaphore The semaphore to acquire one permit from.
173 * @param already_acquired Whether a permit has already been acquired or not.
175 acquire_transaction(semaphore& semaphore, bool already_acquired = false)
176 : semaphore_(semaphore)
179 if (!already_acquired)
180 semaphore_.acquire();
184 * Destructor that will release one permit if commit() has not been called.
186 ~acquire_transaction()
189 semaphore_.release();
193 * Ensure that the acquired permit is kept on destruction.