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_; default_barrier_reseterboost::thread_detail::default_barrier_reseter39 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 default_barrier_reseterboost::thread_detail::default_barrier_reseter46 default_barrier_reseter(default_barrier_reseter const& other) BOOST_NOEXCEPT : 47 size_(other.size_) 48 { 49 } default_barrier_reseterboost::thread_detail::default_barrier_reseter50 default_barrier_reseter(BOOST_THREAD_RV_REF(default_barrier_reseter) other) BOOST_NOEXCEPT : 51 size_(BOOST_THREAD_RV(other).size_) 52 { 53 } 54 operator ()boost::thread_detail::default_barrier_reseter55 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> void_functor_barrier_reseterboost::thread_detail::void_functor_barrier_reseter66 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> void_functor_barrier_reseterboost::thread_detail::void_functor_barrier_reseter70 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 void_functor_barrier_reseterboost::thread_detail::void_functor_barrier_reseter77 void_functor_barrier_reseter(void_functor_barrier_reseter const& other) BOOST_NOEXCEPT : 78 size_(other.size_), fct_(other.fct_) 79 { 80 } void_functor_barrier_reseterboost::thread_detail::void_functor_barrier_reseter81 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 operator ()boost::thread_detail::void_functor_barrier_reseter87 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_)(); void_fct_ptr_barrier_reseterboost::thread_detail::void_fct_ptr_barrier_reseter97 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 void_fct_ptr_barrier_reseterboost::thread_detail::void_fct_ptr_barrier_reseter104 void_fct_ptr_barrier_reseter(void_fct_ptr_barrier_reseter const& other) BOOST_NOEXCEPT : 105 size_(other.size_), fct_(other.fct_) 106 { 107 } void_fct_ptr_barrier_reseterboost::thread_detail::void_fct_ptr_barrier_reseter108 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 } operator ()boost::thread_detail::void_fct_ptr_barrier_reseter112 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 { check_counter(unsigned int count)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 barrier(unsigned int count)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> barrier(unsigned int count,BOOST_THREAD_RV_REF (F)funct,typename enable_if<typename is_void<typename result_of<F ()>::type>::type,dummy * >::type=0)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> barrier(unsigned int count,F & funct,typename enable_if<typename is_void<typename result_of<F ()>::type>::type,dummy * >::type=0)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> barrier(unsigned int count,BOOST_THREAD_RV_REF (F)funct,typename enable_if<typename is_same<typename result_of<F ()>::type,unsigned int>::type,dummy * >::type=0)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> barrier(unsigned int count,F & funct,typename enable_if<typename is_same<typename result_of<F ()>::type,unsigned int>::type,dummy * >::type=0)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 barrier(unsigned int count,void (* funct)())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 } barrier(unsigned int count,unsigned int (* funct)())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 wait()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 count_down_and_wait()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