1 | // Copyright (C) 2002-2003 |
2 | // David Moore, William E. Kempf |
3 | // Copyright (C) 2007-8 Anthony Williams |
4 | // (C) Copyright 2013 Vicente J. Botet Escriba |
5 | // |
6 | // Distributed under the Boost Software License, Version 1.0. (See accompanying |
7 | // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) |
8 | |
9 | #ifndef BOOST_BARRIER_JDM030602_HPP |
10 | #define BOOST_BARRIER_JDM030602_HPP |
11 | |
12 | #include <boost/thread/detail/config.hpp> |
13 | #include <boost/thread/detail/delete.hpp> |
14 | |
15 | #include <boost/throw_exception.hpp> |
16 | #include <boost/thread/mutex.hpp> |
17 | #include <boost/thread/lock_types.hpp> |
18 | #include <boost/thread/condition_variable.hpp> |
19 | #include <string> |
20 | #include <stdexcept> |
21 | #include <boost/thread/detail/nullary_function.hpp> |
22 | #include <boost/type_traits/is_same.hpp> |
23 | #include <boost/type_traits/is_void.hpp> |
24 | #include <boost/core/enable_if.hpp> |
25 | #include <boost/utility/result_of.hpp> |
26 | |
27 | #include <boost/config/abi_prefix.hpp> |
28 | |
29 | namespace boost |
30 | { |
31 | namespace thread_detail |
32 | { |
33 | typedef detail::nullary_function<void()> void_completion_function; |
34 | typedef detail::nullary_function<size_t()> size_completion_function; |
35 | |
36 | struct default_barrier_reseter |
37 | { |
38 | unsigned int size_; |
39 | default_barrier_reseter(unsigned int size) : |
40 | size_(size) |
41 | { |
42 | } |
43 | BOOST_THREAD_MOVABLE(default_barrier_reseter) |
44 | //BOOST_THREAD_COPYABLE_AND_MOVABLE(default_barrier_reseter) |
45 | |
46 | default_barrier_reseter(default_barrier_reseter const& other) BOOST_NOEXCEPT : |
47 | size_(other.size_) |
48 | { |
49 | } |
50 | default_barrier_reseter(BOOST_THREAD_RV_REF(default_barrier_reseter) other) BOOST_NOEXCEPT : |
51 | size_(BOOST_THREAD_RV(other).size_) |
52 | { |
53 | } |
54 | |
55 | unsigned int operator()() |
56 | { |
57 | return size_; |
58 | } |
59 | }; |
60 | |
61 | struct void_functor_barrier_reseter |
62 | { |
63 | unsigned int size_; |
64 | void_completion_function fct_; |
65 | template <typename F> |
66 | void_functor_barrier_reseter(unsigned int size, BOOST_THREAD_RV_REF(F) funct) |
67 | : size_(size), fct_(boost::move(funct)) |
68 | {} |
69 | template <typename F> |
70 | void_functor_barrier_reseter(unsigned int size, F& funct) |
71 | : size_(size), fct_(funct) |
72 | {} |
73 | |
74 | BOOST_THREAD_MOVABLE(void_functor_barrier_reseter) |
75 | //BOOST_THREAD_COPYABLE_AND_MOVABLE(void_functor_barrier_reseter) |
76 | |
77 | void_functor_barrier_reseter(void_functor_barrier_reseter const& other) BOOST_NOEXCEPT : |
78 | size_(other.size_), fct_(other.fct_) |
79 | { |
80 | } |
81 | void_functor_barrier_reseter(BOOST_THREAD_RV_REF(void_functor_barrier_reseter) other) BOOST_NOEXCEPT : |
82 | size_(BOOST_THREAD_RV(other).size_), fct_(BOOST_THREAD_RV(other).fct_) |
83 | //size_(BOOST_THREAD_RV(other).size_), fct_(boost::move(BOOST_THREAD_RV(other).fct_)) |
84 | { |
85 | } |
86 | |
87 | unsigned int operator()() |
88 | { |
89 | fct_(); |
90 | return size_; |
91 | } |
92 | }; |
93 | struct void_fct_ptr_barrier_reseter |
94 | { |
95 | unsigned int size_; |
96 | void(*fct_)(); |
97 | void_fct_ptr_barrier_reseter(unsigned int size, void(*funct)()) : |
98 | size_(size), fct_(funct) |
99 | { |
100 | } |
101 | BOOST_THREAD_MOVABLE(void_fct_ptr_barrier_reseter) |
102 | //BOOST_THREAD_COPYABLE_AND_MOVABLE(void_fct_ptr_barrier_reseter) |
103 | |
104 | void_fct_ptr_barrier_reseter(void_fct_ptr_barrier_reseter const& other) BOOST_NOEXCEPT : |
105 | size_(other.size_), fct_(other.fct_) |
106 | { |
107 | } |
108 | void_fct_ptr_barrier_reseter(BOOST_THREAD_RV_REF(void_fct_ptr_barrier_reseter) other) BOOST_NOEXCEPT : |
109 | size_(BOOST_THREAD_RV(other).size_), fct_(BOOST_THREAD_RV(other).fct_) |
110 | { |
111 | } |
112 | unsigned int operator()() |
113 | { |
114 | fct_(); |
115 | return size_; |
116 | } |
117 | }; |
118 | } |
119 | //BOOST_THREAD_DCL_MOVABLE(thread_detail::default_barrier_reseter) |
120 | //BOOST_THREAD_DCL_MOVABLE(thread_detail::void_functor_barrier_reseter) |
121 | //BOOST_THREAD_DCL_MOVABLE(thread_detail::void_fct_ptr_barrier_reseter) |
122 | |
123 | class barrier |
124 | { |
125 | static inline unsigned int check_counter(unsigned int count) |
126 | { |
127 | if (count == 0) boost::throw_exception( |
128 | thread_exception(system::errc::invalid_argument, "barrier constructor: count cannot be zero." )); |
129 | return count; |
130 | } |
131 | struct dummy |
132 | { |
133 | }; |
134 | |
135 | public: |
136 | BOOST_THREAD_NO_COPYABLE( barrier) |
137 | |
138 | explicit barrier(unsigned int count) : |
139 | m_count(check_counter(count)), m_generation(0), fct_(BOOST_THREAD_MAKE_RV_REF(thread_detail::default_barrier_reseter(count))) |
140 | { |
141 | } |
142 | |
143 | template <typename F> |
144 | barrier( |
145 | unsigned int count, |
146 | BOOST_THREAD_RV_REF(F) funct, |
147 | typename enable_if< |
148 | typename is_void<typename result_of<F()>::type>::type, dummy* |
149 | >::type=0 |
150 | ) |
151 | : m_count(check_counter(count)), |
152 | m_generation(0), |
153 | fct_(BOOST_THREAD_MAKE_RV_REF(thread_detail::void_functor_barrier_reseter(count, |
154 | boost::move(funct))) |
155 | ) |
156 | { |
157 | } |
158 | template <typename F> |
159 | barrier( |
160 | unsigned int count, |
161 | F &funct, |
162 | typename enable_if< |
163 | typename is_void<typename result_of<F()>::type>::type, dummy* |
164 | >::type=0 |
165 | ) |
166 | : m_count(check_counter(count)), |
167 | m_generation(0), |
168 | fct_(BOOST_THREAD_MAKE_RV_REF(thread_detail::void_functor_barrier_reseter(count, |
169 | funct)) |
170 | ) |
171 | { |
172 | } |
173 | |
174 | template <typename F> |
175 | barrier( |
176 | unsigned int count, |
177 | BOOST_THREAD_RV_REF(F) funct, |
178 | typename enable_if< |
179 | typename is_same<typename result_of<F()>::type, unsigned int>::type, dummy* |
180 | >::type=0 |
181 | ) |
182 | : m_count(check_counter(count)), |
183 | m_generation(0), |
184 | fct_(boost::move(funct)) |
185 | { |
186 | } |
187 | template <typename F> |
188 | barrier( |
189 | unsigned int count, |
190 | F& funct, |
191 | typename enable_if< |
192 | typename is_same<typename result_of<F()>::type, unsigned int>::type, dummy* |
193 | >::type=0 |
194 | ) |
195 | : m_count(check_counter(count)), |
196 | m_generation(0), |
197 | fct_(funct) |
198 | { |
199 | } |
200 | |
201 | barrier(unsigned int count, void(*funct)()) : |
202 | m_count(check_counter(count)), m_generation(0), |
203 | fct_(funct |
204 | ? BOOST_THREAD_MAKE_RV_REF(thread_detail::size_completion_function(BOOST_THREAD_MAKE_RV_REF(thread_detail::void_fct_ptr_barrier_reseter(count, funct)))) |
205 | : BOOST_THREAD_MAKE_RV_REF(thread_detail::size_completion_function(BOOST_THREAD_MAKE_RV_REF(thread_detail::default_barrier_reseter(count)))) |
206 | ) |
207 | { |
208 | } |
209 | barrier(unsigned int count, unsigned int(*funct)()) : |
210 | m_count(check_counter(count)), m_generation(0), |
211 | fct_(funct |
212 | ? BOOST_THREAD_MAKE_RV_REF(thread_detail::size_completion_function(funct)) |
213 | : BOOST_THREAD_MAKE_RV_REF(thread_detail::size_completion_function(BOOST_THREAD_MAKE_RV_REF(thread_detail::default_barrier_reseter(count)))) |
214 | ) |
215 | { |
216 | } |
217 | |
218 | bool wait() |
219 | { |
220 | boost::unique_lock < boost::mutex > lock(m_mutex); |
221 | unsigned int gen = m_generation; |
222 | |
223 | if (--m_count == 0) |
224 | { |
225 | m_generation++; |
226 | m_count = static_cast<unsigned int>(fct_()); |
227 | BOOST_ASSERT(m_count != 0); |
228 | lock.unlock(); |
229 | m_cond.notify_all(); |
230 | return true; |
231 | } |
232 | |
233 | while (gen == m_generation) |
234 | m_cond.wait(lock); |
235 | return false; |
236 | } |
237 | |
238 | void count_down_and_wait() |
239 | { |
240 | wait(); |
241 | } |
242 | |
243 | private: |
244 | mutex m_mutex; |
245 | condition_variable m_cond; |
246 | unsigned int m_count; |
247 | unsigned int m_generation; |
248 | thread_detail::size_completion_function fct_; |
249 | }; |
250 | |
251 | } // namespace boost |
252 | |
253 | #include <boost/config/abi_suffix.hpp> |
254 | |
255 | #endif |
256 | |