1[/ 2 (C) Copyright 2008-9 Anthony Williams. 3 (C) Copyright 12 Vicente J. Botet Escriba. 4 Distributed under the Boost Software License, Version 1.0. 5 (See accompanying file LICENSE_1_0.txt or copy at 6 http://www.boost.org/LICENSE_1_0.txt). 7] 8 9[section:ScopedThreads Scoped Threads] 10 11[heading Synopsis] 12 13 //#include <boost/thread/scoped_thread.hpp> 14 15 struct detach; 16 struct join_if_joinable; 17 struct interrupt_and_join_if_joinable; 18 template <class CallableThread = join_if_joinable, class Thread = thread> 19 class strict_scoped_thread; 20 template <class CallableThread = join_if_joinable, class Thread = thread> 21 class scoped_thread; 22 template <class CallableThread, class Thread = thread> 23 void swap(scoped_thread<Callable, Thread>& lhs, scoped_threadCallable, Thread>& rhs) noexcept; 24 25[section:motivation Motivation] 26Based on the scoped_thread class defined in C++ Concurrency in Action Boost.Thread defines a thread wrapper class that instead of calling terminate if the thread is joinable on destruction, call a specific action given as template parameter. 27 28While the scoped_thread class defined in C++ Concurrency in Action is closer to strict_scoped_thread class that doesn't allows any change in the wrapped thread, Boost.Thread provides a class scoped_thread that provides the same non-deprecated interface as __thread. 29 30[endsect] 31 32[section:tutorial Tutorial] 33 34Scoped Threads are wrappers around a thread that allows the user to state what to do at destruction time. One of the common uses is to join the thread at destruction time so this is the default behavior. This is the single difference respect to a thread. While thread call std::terminate() on the destructor if the thread is joinable, strict_scoped_thread<> or scoped_thread<> join the thread if joinable. 35 36The difference between strict_scoped_thread and scoped_thread is that the strict_scoped_thread hides completely the owned thread and so the user can do nothing with the owned thread other than the specific action given as parameter, while scoped_thread provide the same interface as __thread and forwards all the operations. 37 38 boost::strict_scoped_thread<> t1((boost::thread(f))); 39 //t1.detach(); // compile fails 40 boost::scoped_thread<> t2((boost::thread(f))); 41 t2.detach(); 42 43[endsect] 44 45[section:thread_functors Free Thread Functors] 46 47 //#include <boost/thread/scoped_thread.hpp> 48 49 struct detach; 50 struct join_if_joinable; 51 struct interrupt_and_join_if_joinable; 52 53 54[section:detach Functor `detach`] 55 56 struct detach 57 { 58 template <class Thread> 59 void operator()(Thread& t) 60 { 61 t.detach(); 62 } 63 }; 64[endsect] 65[section:join_if_joinable Functor `join_if_joinable`] 66 67 struct join_if_joinable 68 { 69 template <class Thread> 70 void operator()(Thread& t) 71 { 72 if (t.joinable()) 73 { 74 t.join(); 75 } 76 } 77 }; 78 79[endsect] 80 81[section:interrupt_and_join_if_joinable Functor `interrupt_and_join_if_joinable`] 82 83 struct interrupt_and_join_if_joinable 84 { 85 template <class Thread> 86 void operator()(Thread& t) 87 { 88 t.interrupt(); 89 if (t.joinable()) 90 { 91 t.join(); 92 } 93 } 94 }; 95[endsect] 96 97[endsect] 98 99[section:strict_scoped_thread Class `strict_scoped_thread`] 100 101 // #include <boost/thread/scoped_thread.hpp> 102 103 template <class CallableThread = join_if_joinable, class Thread = ::boost::thread> 104 class strict_scoped_thread 105 { 106 thread t_; // for exposition purposes only 107 public: 108 109 strict_scoped_thread(strict_scoped_thread const&) = delete; 110 strict_scoped_thread& operator=(strict_scoped_thread const&) = delete; 111 112 explicit strict_scoped_thread(Thread&& t) noexcept; 113 template <typename F&&, typename ...Args> 114 explicit strict_scoped_thread(F&&, Args&&...); 115 116 ~strict_scoped_thread(); 117 118 }; 119 120 121RAII __thread wrapper adding a specific destroyer allowing to master what can be done at destruction time. 122 123CallableThread: A callable `void(thread&)`. 124 125The default is a `join_if_joinable`. 126 127 128Thread destructor terminates the program if the __thread is joinable. 129This wrapper can be used to join the thread before destroying it. 130 131[heading Example] 132 133 boost::strict_scoped_thread<> t((boost::thread(F))); 134 135[section:default_constructor Constructor from a __thread] 136 137 explicit strict_scoped_thread(Thread&& t) noexcept; 138 139[variablelist 140 141[[Effects:] [move the thread to own `t_`]] 142 143[[Throws:] [Nothing]] 144 145] 146 147[endsect] 148 149 150[section:call_constructor Move Constructor from a Callable] 151 152 template <typename F&&, typename ...Args> 153 explicit strict_scoped_thread(F&&, Args&&...); 154 155[variablelist 156 157[[Effects:] [Construct an internal thread in place.]] 158 159[[Postconditions:] [`*this.t_` refers to the newly created thread of execution and `this->get_id()!=thread::id()`.]] 160 161[[Throws:] [Any exception the thread construction can throw.]] 162 163] 164 165[endsect] 166 167[section:destructor Destructor] 168 169 ~strict_scoped_thread(); 170 171[variablelist 172 173[[Effects:] [Equivalent to `CallableThread()(t_)`. ]] 174 175[[Throws:] [Nothing: The `CallableThread()(t_)` should not throw when joining the thread as the scoped variable is on a scope outside the thread function.]] 176 177] 178 179[endsect] 180 181[endsect] 182 183[section:scoped_thread Class `scoped_thread`] 184 185 #include <boost/thread/scoped_thread.hpp> 186 187 template <class CallableThread, class Thread = thread> 188 class scoped_thread 189 { 190 thread t_; // for exposition purposes only 191 public: 192 scoped_thread() noexcept; 193 scoped_thread(const scoped_thread&) = delete; 194 scoped_thread& operator=(const scoped_thread&) = delete; 195 196 explicit scoped_thread(thread&& th) noexcept; 197 template <typename F&&, typename ...Args> 198 explicit scoped_thread(F&&, Args&&...); 199 200 ~scoped_thread(); 201 202 // move support 203 scoped_thread(scoped_thread && x) noexcept; 204 scoped_thread& operator=(scoped_thread && x) noexcept; 205 206 void swap(scoped_thread& x) noexcept; 207 208 typedef thread::id id; 209 210 id get_id() const noexcept; 211 212 bool joinable() const noexcept; 213 void join(); 214 #ifdef BOOST_THREAD_USES_CHRONO 215 template <class Rep, class Period> 216 bool try_join_for(const chrono::duration<Rep, Period>& rel_time); 217 template <class Clock, class Duration> 218 bool try_join_until(const chrono::time_point<Clock, Duration>& t); 219 #endif 220 221 void detach(); 222 223 static unsigned hardware_concurrency() noexcept; 224 static unsigned physical_concurrency() noexcept; 225 226 typedef thread::native_handle_type native_handle_type; 227 native_handle_type native_handle(); 228 229 #if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS 230 void interrupt(); 231 bool interruption_requested() const noexcept; 232 #endif 233 234 235 }; 236 237 template <class CallableThread, class Thread = thread> 238 void swap(scoped_thread<CallableThread,Thread>& lhs,scoped_thread<CallableThread,Thread>& rhs) noexcept; 239 240 241RAII __thread wrapper adding a specific destroyer allowing to master what can be done at destruction time. 242 243CallableThread: A callable void(thread&). 244The default is join_if_joinable. 245 246Thread destructor terminates the program if the thread is joinable. 247This wrapper can be used to join the thread before destroying it. 248 249Remark: `scoped_thread` is not a __thread as __thread is not designed to be derived from as a polymorphic type. 250 251Anyway `scoped_thread` can be used in most of the contexts a __thread could be used as it has the 252same non-deprecated interface with the exception of the construction. 253 254[heading Example] 255 256 boost::scoped_thread<> t((boost::thread(F))); 257 t.interrupt(); 258 259 260[section:default_constructor Default Constructor] 261 262 scoped_thread() noexcept; 263 264[variablelist 265 266[[Effects:] [Constructs a scoped_thread instance that wraps to __not_a_thread__.]] 267 268[[Postconditions:] [`this->get_id()==thread::id()`]] 269 270[[Throws:] [Nothing]] 271 272] 273 274[endsect] 275 276[section:move_constructor Move Constructor] 277 278 scoped_thread(scoped_thread&& other) noexcept; 279 280[variablelist 281 282[[Effects:] [Transfers ownership of the scoped_thread managed by `other` (if any) to the newly constructed scoped_thread instance.]] 283 284[[Postconditions:] [`other.get_id()==thread::id()` and `get_id()` returns the value of `other.get_id()` prior to the construction]] 285 286[[Throws:] [Nothing]] 287 288] 289 290[endsect] 291 292[section:move_assignment Move assignment operator] 293 294 scoped_thread& operator=(scoped_thread&& other) noexcept; 295 296[variablelist 297 298[[Effects:] [Transfers ownership of the scoped_thread managed by `other` (if 299any) to `*this` after having called to `CallableThread()(t_)`. 300 301]] 302 303[[Postconditions:] [`other->get_id()==thread::id()` and `get_id()` returns the value of `other.get_id()` prior to the assignment.]] 304 305[[Throws:] [Nothing: The `CallableThread()(t_)` should not throw when joining the thread as the scoped variable is on a scope outside the thread function.]] 306 307 308] 309 310[endsect] 311 312[section:thread_constructor Move Constructor from a __thread] 313 314 scoped_thread(thread&& t); 315 316[variablelist 317 318[[Effects:] [Transfers ownership of the thread managed by `other` (if any) to the newly constructed scoped_thread instance.]] 319 320[[Postconditions:] [other.get_id()==thread::id() and get_id() returns the value of other.get_id() prior to the construction.]] 321 322[[Throws:] [Nothing]] 323 324] 325 326[endsect] 327 328[section:call_constructor Move Constructor from a Callable] 329 330 template <typename F&&, typename ...Args> 331 explicit scoped_thread(F&&, Args&&...); 332 333[variablelist 334 335[[Effects:] [Construct an internal thread in place.]] 336 337[[Postconditions:] [`*this.t_` refers to the newly created thread of execution and `this->get_id()!=thread::id()`.]] 338 339[[Throws:] [Any exception the thread construction can throw.]] 340 341] 342 343[endsect] 344 345 346[section:destructor Destructor] 347 348 ~scoped_thread(); 349 350[variablelist 351 352[[Effects:] [Equivalent to `CallableThread()(t_)`. ]] 353 354[[Throws:] [Nothing: The `CallableThread()(t_)` should not throw when joining the thread as the scoped variable is on a scope outside the thread function.]] 355 356] 357 358[endsect] 359 360 361[section:joinable Member function `joinable()`] 362 363 bool joinable() const noexcept; 364 365[variablelist 366 367[[Returns:] [Equivalent to return t_.joinable().]] 368 369[[Throws:] [Nothing]] 370 371] 372 373 374[endsect] 375 376[section:join Member function `join()`] 377 378 void join(); 379 380[variablelist 381 382[[Effects:] [Equivalent to t_.join().]] 383 384] 385 386[endsect] 387 388[section:try_join_for Member function `try_join_for()`] 389 390 template <class Rep, class Period> 391 bool try_join_for(const chrono::duration<Rep, Period>& rel_time); 392 393[variablelist 394 395[[Effects:] [Equivalent to return `t_.try_join_for(rel_time)`.]] 396 397] 398 399[endsect] 400 401[section:try_join_until Member function `try_join_until()`] 402 403 template <class Clock, class Duration> 404 bool try_join_until(const chrono::time_point<Clock, Duration>& abs_time); 405 406[variablelist 407 408[[Effects:] [Equivalent to return `t_.try_join_until(abs_time)`.]] 409 410] 411 412[endsect] 413 414 415 416[section:detach Member function `detach()`] 417 418 void detach(); 419 420[variablelist 421 422[[Effects:] [Equivalent to `t_.detach()`.]] 423 424] 425 426[endsect] 427 428 429[section:get_id Member function `get_id()`] 430 431 thread::id get_id() const noexcept; 432 433[variablelist 434 435[[Effects:] [Equivalent to return `t_.get_id()`.]] 436 437] 438 439[endsect] 440 441[section:interrupt Member function `interrupt()`] 442 443 void interrupt(); 444 445[variablelist 446 447[[Effects:] [Equivalent to `t_.interrupt()`.]] 448 449] 450 451 452[endsect] 453 454[section:hardware_concurrency Static member function `hardware_concurrency()`] 455 456 unsigned hardware_concurrency() noexecpt; 457 458[variablelist 459 460[[Effects:] [Equivalent to return `thread::hardware_concurrency()`.]] 461 462] 463 464[endsect] 465 466 467[section:physical_concurrency Static member function `physical_concurrency()`] 468 469 unsigned physical_concurrency() noexecpt; 470 471[variablelist 472 473[[Effects:] [Equivalent to return `thread::physical_concurrency()`.]] 474 475] 476 477[endsect] 478 479 480[section:nativehandle Member function `native_handle()`] 481 482 typedef thread::native_handle_type native_handle_type; 483 native_handle_type native_handle(); 484 485[variablelist 486 487[[Effects:] [Equivalent to return `t_.native_handle()`.]] 488 489] 490 491[endsect] 492 493[section:swap Member function `swap()`] 494 495 void swap(scoped_thread& other) noexcept; 496 497[variablelist 498 499[[Effects:] [Equivalent `t_.swap(other.t_)`.]] 500 501] 502 503[endsect] 504 505 506 507[endsect] 508[section:non_member_swap Non-member function `swap(scoped_thread&,scoped_thread&)`] 509 510 #include <boost/thread/scoped_thread.hpp> 511 512 template <class CallableThread, class Thread = thread> 513 void swap(scoped_thread<Callable, Thread>& lhs, scoped_threadCallable, Thread>& rhs) noexcept; 514 515[variablelist 516 517[[Effects:] [`lhs.swap(rhs)`.]] 518 519] 520 521[endsect] 522[endsect] 523