1 // Distributed under the Boost Software License, Version 1.0. (See
2 // accompanying file LICENSE_1_0.txt or copy at
3 // http://www.boost.org/LICENSE_1_0.txt)
4 // (C) Copyright 2013 Vicente J. Botet Escriba
6 #ifndef BOOST_THREAD_COMPLETION_LATCH_HPP
7 #define BOOST_THREAD_COMPLETION_LATCH_HPP
9 #include <boost/thread/detail/config.hpp>
10 #include <boost/thread/detail/delete.hpp>
11 #include <boost/thread/detail/counter.hpp>
13 #include <boost/thread/mutex.hpp>
14 #include <boost/thread/lock_types.hpp>
15 #include <boost/thread/condition_variable.hpp>
16 #include <boost/chrono/duration.hpp>
17 #include <boost/chrono/time_point.hpp>
18 #include <boost/assert.hpp>
19 //#include <boost/thread/detail/nullary_function.hpp>
20 #include <boost/thread/csbl/functional.hpp>
22 #include <boost/config/abi_prefix.hpp>
26 namespace thread_detail
32 class completion_latch
35 /// the implementation defined completion function type
36 //typedef detail::nullary_function<void()> completion_function;
37 typedef csbl::function<void()> completion_function;
38 /// noop completion function factory
39 static completion_function noop()
41 return completion_function(&thread_detail::noop);
46 friend struct around_wait;
49 completion_latch &that_;
50 boost::unique_lock<boost::mutex> &lk_;
51 around_wait(completion_latch &that, boost::unique_lock<boost::mutex> &lk)
52 : that_(that), lk_(lk)
54 that_.leavers_.cond_.wait(lk, detail::counter_is_zero(that_.leavers_));
55 that_.waiters_.inc_and_notify_all();
56 that_.leavers_.cond_.wait(lk, detail::counter_is_not_zero(that_.leavers_));
60 that_.waiters_.dec_and_notify_all();
64 bool count_down(unique_lock<mutex> &lk)
66 BOOST_ASSERT(count_ > 0);
69 waiters_.cond_.wait(lk, detail::counter_is_not_zero(waiters_));
70 leavers_.assign_and_notify_all(waiters_);
71 count_.cond_.notify_all();
72 waiters_.cond_.wait(lk, detail::counter_is_zero(waiters_));
73 leavers_.assign_and_notify_all(0);
82 BOOST_THREAD_NO_COPYABLE( completion_latch )
84 /// Constructs a latch with a given count.
85 completion_latch(std::size_t count) :
86 count_(count), funct_(noop()), waiters_(0), leavers_(0)
90 /// Constructs a latch with a given count and a completion function.
92 completion_latch(std::size_t count, BOOST_THREAD_RV_REF(F) funct) :
94 funct_(boost::move(funct)),
99 completion_latch(std::size_t count, void(*funct)()) :
100 count_(count), funct_(funct), waiters_(0), leavers_(0)
109 /// Blocks until the latch has counted down to zero.
112 boost::unique_lock<boost::mutex> lk(mutex_);
113 around_wait aw(*this, lk);
114 count_.cond_.wait(lk, detail::counter_is_zero(count_));
117 /// @return true if the internal counter is already 0, false otherwise
120 boost::unique_lock<boost::mutex> lk(mutex_);
121 around_wait aw(*this, lk);
122 return (count_ == 0);
125 /// try to wait for a specified amount of time
126 /// @return whether there is a timeout or not.
127 template <class Rep, class Period>
128 cv_status wait_for(const chrono::duration<Rep, Period>& rel_time)
130 boost::unique_lock<boost::mutex> lk(mutex_);
131 around_wait aw(*this, lk);
132 return count_.cond_.wait_for(lk, rel_time, detail::counter_is_zero(count_))
133 ? cv_status::no_timeout
134 : cv_status::timeout;
137 /// try to wait until the specified time_point is reached
138 /// @return whether there is a timeout or not.
139 template <class Clock, class Duration>
140 cv_status wait_until(const chrono::time_point<Clock, Duration>& abs_time)
142 boost::unique_lock<boost::mutex> lk(mutex_);
143 around_wait aw(*this, lk);
144 return count_.cond_.wait_until(lk, abs_time, detail::counter_is_zero(count_))
145 ? cv_status::no_timeout
146 : cv_status::timeout;
149 /// Decrement the count and notify anyone waiting if we reach zero.
150 /// @Requires count must be greater than 0
153 unique_lock<mutex> lk(mutex_);
161 /// Decrement the count and notify anyone waiting if we reach zero.
162 /// Blocks until the latch has counted down to zero.
163 /// @Requires count must be greater than 0
164 void count_down_and_wait()
166 boost::unique_lock<boost::mutex> lk(mutex_);
171 around_wait aw(*this, lk);
172 count_.cond_.wait(lk, detail::counter_is_zero(count_));
176 count_down_and_wait();
179 /// Reset the counter
180 /// #Requires This method may only be invoked when there are no other threads currently inside the count_down_and_wait() method.
181 void reset(std::size_t count)
183 boost::lock_guard<boost::mutex> lk(mutex_);
184 //BOOST_ASSERT(count_ == 0);
188 /// Resets the latch with the new completion function.
189 /// The next time the internal count reaches 0, this function will be invoked.
190 /// This completion function may only be invoked when there are no other threads
191 /// currently inside the count_down and wait related functions.
192 /// It may also be invoked from within the registered completion function.
193 /// @Returns the old completion function if any or noop if
195 #ifdef BOOST_NO_CXX11_HDR_FUNCTIONAL
196 template <typename F>
197 completion_function then(BOOST_THREAD_RV_REF(F) funct)
199 boost::lock_guard<boost::mutex> lk(mutex_);
200 completion_function tmp(funct_);
201 funct_ = boost::move(funct);
205 completion_function then(void(*funct)())
207 boost::lock_guard<boost::mutex> lk(mutex_);
208 completion_function tmp(funct_);
209 funct_ = completion_function(funct);
215 detail::counter count_;
216 completion_function funct_;
217 detail::counter waiters_;
218 detail::counter leavers_;
223 #include <boost/config/abi_suffix.hpp>