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 2009-2012 Anthony Williams 5 // (C) Copyright 2012 Vicente J. Botet Escriba 6 7 // Based on the Anthony's idea of scoped_thread in CCiA 8 9 #ifndef BOOST_THREAD_SCOPED_THREAD_HPP 10 #define BOOST_THREAD_SCOPED_THREAD_HPP 11 12 #include <boost/thread/detail/config.hpp> 13 #include <boost/thread/detail/delete.hpp> 14 #include <boost/thread/detail/move.hpp> 15 #include <boost/thread/thread_functors.hpp> 16 #include <boost/thread/thread_only.hpp> 17 18 #include <boost/config/abi_prefix.hpp> 19 20 namespace boost 21 { 22 23 /** 24 * RAI @c thread wrapper adding a specific destroyer allowing to master what can be done at destruction time. 25 * 26 * CallableThread: A callable void(thread&) . 27 * The default is a join_if_joinable. 28 * 29 * thread std/boost::thread destructor terminates the program if the thread is not joinable. 30 * Having a wrapper that can join the thread before destroying it seems a natural need. 31 * 32 * Example: 33 * 34 * boost::strict_scoped_thread<> t((boost::thread(F))); 35 * 36 */ 37 template <class CallableThread = join_if_joinable, class Thread=::boost::thread> 38 class strict_scoped_thread 39 { 40 Thread t_; 41 struct dummy; 42 public: 43 44 BOOST_THREAD_NO_COPYABLE( strict_scoped_thread) /// non copyable 45 46 /* 47 * 48 */ 49 #if ! defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) 50 template <class F, class ...Args, typename = typename disable_if<is_same<typename decay<F>::type, Thread>, void* >::type> strict_scoped_thread(BOOST_THREAD_FWD_REF (F)f,BOOST_THREAD_FWD_REF (Args)...args)51 explicit strict_scoped_thread(BOOST_THREAD_FWD_REF(F) f, BOOST_THREAD_FWD_REF(Args)... args) : 52 t_(boost::forward<F>(f), boost::forward<Args>(args)...) {} 53 #else 54 template <class F> 55 explicit strict_scoped_thread(BOOST_THREAD_FWD_REF(F) f, 56 typename disable_if<is_same<typename decay<F>::type, Thread>, void* >::type=0) : 57 t_(boost::forward<F>(f)) {} 58 template <class F, class A1> 59 strict_scoped_thread(BOOST_THREAD_FWD_REF(F) f, BOOST_THREAD_FWD_REF(A1) a1) : 60 t_(boost::forward<F>(f), boost::forward<A1>(a1)) {} 61 template <class F, class A1, class A2> 62 strict_scoped_thread(BOOST_THREAD_FWD_REF(F) f, BOOST_THREAD_FWD_REF(A1) a1, BOOST_THREAD_FWD_REF(A2) a2) : 63 t_(boost::forward<F>(f), boost::forward<A1>(a1), boost::forward<A2>(a2)) {} 64 template <class F, class A1, class A2, class A3> 65 strict_scoped_thread(BOOST_THREAD_FWD_REF(F) f, BOOST_THREAD_FWD_REF(A1) a1, BOOST_THREAD_FWD_REF(A2) a2, BOOST_THREAD_FWD_REF(A3) a3) : 66 t_(boost::forward<F>(f), boost::forward<A1>(a1), boost::forward<A2>(a2), boost::forward<A3>(a3)) {} 67 #endif 68 69 /** 70 * Constructor from the thread to own. 71 * 72 * @param t: the thread to own. 73 * 74 * Effects: move the thread to own @c t. 75 */ strict_scoped_thread(BOOST_THREAD_RV_REF (Thread)t)76 explicit strict_scoped_thread(BOOST_THREAD_RV_REF(Thread) t) BOOST_NOEXCEPT : 77 t_(boost::move(t)) 78 { 79 } 80 81 /** 82 * Destructor 83 * Effects: Call the CallableThread functor before destroying the owned thread. 84 * Remark: The CallableThread should not throw when joining the thread as the scoped variable is on a scope outside the thread function. 85 */ ~strict_scoped_thread()86 ~strict_scoped_thread() 87 { 88 CallableThread on_destructor; 89 90 on_destructor(t_); 91 } 92 93 }; 94 95 /** 96 * RAI @c thread wrapper adding a specific destroyer allowing to master what can be done at destruction time. 97 * 98 * CallableThread: A callable void(thread&) . 99 * The default is join_if_joinable. 100 * 101 * thread std::thread destructor terminates the program if the thread is not joinable. 102 * Having a wrapper that can join the thread before destroying it seems a natural need. 103 * 104 * Remark: @c scoped_thread is not a @c thread as @c thread is not designed to be derived from as a polymorphic type. 105 * Anyway @c scoped_thread can be used in most of the contexts a @c thread could be used as it has the 106 * same non-deprecated interface with the exception of the construction. 107 * 108 * Example: 109 * 110 * boost::scoped_thread<> t((boost::thread(F))); 111 * t.interrupt(); 112 * 113 */ 114 template <class CallableThread = join_if_joinable, class Thread=::boost::thread> 115 class scoped_thread 116 { 117 Thread t_; 118 struct dummy; 119 public: 120 121 typedef typename Thread::id id; 122 typedef typename Thread::native_handle_type native_handle_type; 123 124 BOOST_THREAD_MOVABLE_ONLY( scoped_thread) /// Movable only 125 126 /** 127 * Default Constructor. 128 * 129 * Effects: wraps a not-a-thread. 130 */ scoped_thread()131 scoped_thread() BOOST_NOEXCEPT: 132 t_() 133 { 134 } 135 136 /** 137 * 138 */ 139 140 #if ! defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) 141 template <class F, class ...Args, typename = typename disable_if<is_same<typename decay<F>::type, Thread>, void* >::type> scoped_thread(BOOST_THREAD_FWD_REF (F)f,BOOST_THREAD_FWD_REF (Args)...args)142 explicit scoped_thread(BOOST_THREAD_FWD_REF(F) f, BOOST_THREAD_FWD_REF(Args)... args) : 143 t_(boost::forward<F>(f), boost::forward<Args>(args)...) {} 144 #else 145 template <class F> scoped_thread(BOOST_THREAD_FWD_REF (F)f,typename disable_if<is_same<typename decay<F>::type,Thread>,void * >::type=0)146 explicit scoped_thread(BOOST_THREAD_FWD_REF(F) f, 147 typename disable_if<is_same<typename decay<F>::type, Thread>, void* >::type=0) : 148 t_(boost::forward<F>(f)) {} 149 template <class F, class A1> scoped_thread(BOOST_THREAD_FWD_REF (F)f,BOOST_THREAD_FWD_REF (A1)a1)150 scoped_thread(BOOST_THREAD_FWD_REF(F) f, BOOST_THREAD_FWD_REF(A1) a1) : 151 t_(boost::forward<F>(f), boost::forward<A1>(a1)) {} 152 template <class F, class A1, class A2> scoped_thread(BOOST_THREAD_FWD_REF (F)f,BOOST_THREAD_FWD_REF (A1)a1,BOOST_THREAD_FWD_REF (A2)a2)153 scoped_thread(BOOST_THREAD_FWD_REF(F) f, BOOST_THREAD_FWD_REF(A1) a1, BOOST_THREAD_FWD_REF(A2) a2) : 154 t_(boost::forward<F>(f), boost::forward<A1>(a1), boost::forward<A2>(a2)) {} 155 template <class F, class A1, class A2, class A3> scoped_thread(BOOST_THREAD_FWD_REF (F)f,BOOST_THREAD_FWD_REF (A1)a1,BOOST_THREAD_FWD_REF (A2)a2,BOOST_THREAD_FWD_REF (A3)a3)156 scoped_thread(BOOST_THREAD_FWD_REF(F) f, BOOST_THREAD_FWD_REF(A1) a1, BOOST_THREAD_FWD_REF(A2) a2, BOOST_THREAD_FWD_REF(A3) a3) : 157 t_(boost::forward<F>(f), boost::forward<A1>(a1), boost::forward<A2>(a2), boost::forward<A3>(a3)) {} 158 159 #endif 160 /** 161 * Constructor from the thread to own. 162 * 163 * @param t: the thread to own. 164 * 165 * Effects: move the thread to own @c t. 166 */ scoped_thread(BOOST_THREAD_RV_REF (Thread)t)167 explicit scoped_thread(BOOST_THREAD_RV_REF(Thread) t) BOOST_NOEXCEPT : 168 t_(boost::move(t)) 169 { 170 } 171 172 // explicit operator Thread() 173 // { 174 // return boost::move(t_); 175 // } 176 177 /** 178 * Move constructor. 179 */ scoped_thread(BOOST_RV_REF (scoped_thread)x)180 scoped_thread(BOOST_RV_REF(scoped_thread) x) BOOST_NOEXCEPT : 181 t_(boost::move(BOOST_THREAD_RV(x).t_)) 182 {} 183 184 /** 185 * Destructor 186 * 187 * Effects: Call the CallableThread functor before destroying the owned thread. 188 */ ~scoped_thread()189 ~scoped_thread() 190 { 191 CallableThread on_destructor; 192 193 on_destructor(t_); 194 } 195 196 /** 197 * Move assignment. 198 */ operator =(BOOST_RV_REF (scoped_thread)x)199 scoped_thread& operator=(BOOST_RV_REF(scoped_thread) x) 200 { 201 CallableThread on_destructor; 202 203 on_destructor(t_); 204 t_ = boost::move(BOOST_THREAD_RV(x).t_); 205 return *this; 206 } 207 208 /** 209 * 210 */ swap(scoped_thread & x)211 void swap(scoped_thread& x) BOOST_NOEXCEPT 212 { 213 t_.swap(x.t_); 214 } 215 216 // forwarded thread functions get_id() const217 inline id get_id() const BOOST_NOEXCEPT 218 { 219 return t_.get_id(); 220 } 221 detach()222 void detach() 223 { 224 t_.detach(); 225 } 226 join()227 void join() 228 { 229 t_.join(); 230 } 231 232 #ifdef BOOST_THREAD_USES_CHRONO 233 template <class Rep, class Period> try_join_for(const chrono::duration<Rep,Period> & rel_time)234 bool try_join_for(const chrono::duration<Rep, Period>& rel_time) 235 { 236 return t_.try_join_for(rel_time); 237 } 238 239 template <class Clock, class Duration> try_join_until(const chrono::time_point<Clock,Duration> & abs_time)240 bool try_join_until(const chrono::time_point<Clock, Duration>& abs_time) 241 { 242 return t_.try_join_until(abs_time); 243 } 244 #endif 245 native_handle()246 native_handle_type native_handle()BOOST_NOEXCEPT 247 { 248 return t_.native_handle(); 249 } 250 joinable() const251 bool joinable() const BOOST_NOEXCEPT 252 { 253 return t_.joinable(); 254 } 255 256 #if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS interrupt()257 void interrupt() 258 { 259 t_.interrupt(); 260 } 261 interruption_requested() const262 bool interruption_requested() const BOOST_NOEXCEPT 263 { 264 return t_.interruption_requested(); 265 } 266 #endif 267 hardware_concurrency()268 static unsigned hardware_concurrency() BOOST_NOEXCEPT 269 { 270 return Thread::hardware_concurrency(); 271 } 272 273 #ifdef BOOST_THREAD_PROVIDES_PHYSICAL_CONCURRENCY physical_concurrency()274 static unsigned physical_concurrency() BOOST_NOEXCEPT 275 { 276 return Thread::physical_concurrency(); 277 } 278 #endif 279 }; 280 281 /** 282 * Effects: swaps the contents of two scoped threads. 283 */ 284 template <class Destroyer, class Thread > swap(scoped_thread<Destroyer,Thread> & lhs,scoped_thread<Destroyer,Thread> & rhs)285 void swap(scoped_thread<Destroyer, Thread>& lhs, scoped_thread<Destroyer, Thread>& rhs) 286 BOOST_NOEXCEPT { 287 return lhs.swap(rhs); 288 } 289 290 typedef scoped_thread<> joining_thread; 291 } 292 #include <boost/config/abi_suffix.hpp> 293 294 #endif 295