1[/ 2 (C) Copyright 2007-8 Anthony Williams. 3 (C) Copyright 2011-12 Vicente J. Botet Escriba. 4 (C) Copyright 2013 Oliver Kowalke. 5 Distributed under the Boost Software License, Version 1.0. 6 (See accompanying file LICENSE_1_0.txt or copy at 7 http://www.boost.org/LICENSE_1_0.txt). 8] 9 10[section:fiber_mgmt Fiber management] 11 12[heading Synopsis] 13 14 #include <boost/fiber/all.hpp> 15 16 namespace boost { 17 namespace fibers { 18 19 class fiber; 20 bool operator<( fiber const& l, fiber const& r) noexcept; 21 void swap( fiber & l, fiber & r) noexcept; 22 23 template< typename SchedAlgo, typename ... Args > 24 void use_scheduling_algorithm( Args && ... args); 25 bool has_ready_fibers(); 26 27 namespace algo { 28 29 struct algorithm; 30 template< typename PROPS > 31 struct algorithm_with_properties; 32 class round_robin; 33 class shared_round_robin; 34 35 }} 36 37 namespace this_fiber { 38 39 fibers::id get_id() noexcept; 40 void yield(); 41 template< typename Clock, typename Duration > 42 void sleep_until( std::chrono::time_point< Clock, Duration > const& abs_time) 43 template< typename Rep, typename Period > 44 void sleep_for( std::chrono::duration< Rep, Period > const& rel_time); 45 template< typename PROPS > 46 PROPS & properties(); 47 48 } 49 50 51[heading Tutorial] 52 53Each __fiber__ represents a micro-thread which will be launched and managed 54cooperatively by a scheduler. Objects of type __fiber__ are move-only. 55 56 boost::fibers::fiber f1; // not-a-fiber 57 58 void f() { 59 boost::fibers::fiber f2( some_fn); 60 61 f1 = std::move( f2); // f2 moved to f1 62 } 63 64 65[heading Launching] 66 67A new fiber is launched by passing an object of a callable type that can be 68invoked with no parameters. 69If the object must not be copied or moved, then ['std::ref] can be used to 70pass in a reference to the function object. In this case, the user must ensure 71that the referenced object outlives the newly-created fiber. 72 73 struct callable { 74 void operator()(); 75 }; 76 77 boost::fibers::fiber copies_are_safe() { 78 callable x; 79 return boost::fibers::fiber( x); 80 } // x is destroyed, but the newly-created fiber has a copy, so this is OK 81 82 boost::fibers::fiber oops() { 83 callable x; 84 return boost::fibers::fiber( std::ref( x) ); 85 } // x is destroyed, but the newly-created fiber still has a reference 86 // this leads to undefined behaviour 87 88The spawned __fiber__ does not immediately start running. It is enqueued in 89the list of ready-to-run fibers, and will run when the scheduler gets around 90to it. 91 92 93[#exceptions] 94[heading Exceptions] 95 96An exception escaping from the function or callable object passed to the __fiber__ 97constructor calls `std::terminate()`. 98If you need to know which exception was thrown, use __future__ or 99__packaged_task__. 100 101 102[heading Detaching] 103 104A __fiber__ can be detached by explicitly invoking the __detach__ member 105function. After __detach__ is called on a fiber object, that object represents 106__not_a_fiber__. The fiber object may then safely be destroyed. 107 108 boost::fibers::fiber( some_fn).detach(); 109 110__boost_fiber__ provides a number of ways to wait for a running fiber to 111complete. You can coordinate even with a detached fiber using a [class_link 112mutex], or [class_link condition_variable], or any of the other [link 113synchronization synchronization objects] provided by the library. 114 115If a detached fiber is still running when the thread[s] main fiber terminates, 116the thread will not shut down. 117 118[heading Joining] 119 120In order to wait for a fiber to finish, the __join__ member function of the 121__fiber__ object can be used. __join__ will block until the __fiber__ object 122has completed. 123 124 void some_fn() { 125 ... 126 } 127 128 boost::fibers::fiber f( some_fn); 129 ... 130 f.join(); 131 132If the fiber has already completed, then __join__ returns immediately and 133the joined __fiber__ object becomes __not_a_fiber__. 134 135 136[heading Destruction] 137 138When a __fiber__ object representing a valid execution context (the fiber is 139__joinable__) is destroyed, the program terminates. If you intend the fiber to 140outlive the __fiber__ object that launched it, use the __detach__ method. 141 142 { 143 boost::fibers::fiber f( some_fn); 144 } // std::terminate() will be called 145 146 { 147 boost::fibers::fiber f(some_fn); 148 f.detach(); 149 } // okay, program continues 150 151 152[#class_fiber_id] 153[heading Fiber IDs] 154 155Objects of class __fiber_id__ can be used to identify fibers. Each running 156__fiber__ has a unique __fiber_id__ obtainable from the corresponding __fiber__ 157by calling the __get_id__ member function. 158Objects of class __fiber_id__ can be copied, and used as keys in associative 159containers: the full range of comparison operators is provided. 160They can also be written to an output stream using the stream insertion 161operator, though the output format is unspecified. 162 163Each instance of __fiber_id__ either refers to some fiber, or __not_a_fiber__. 164Instances that refer to __not_a_fiber__ compare equal to each other, but 165not equal to any instances that refer to an actual fiber. The comparison 166operators on __fiber_id__ yield a total order for every non-equal __fiber_id__. 167 168[#class_launch] 169[heading Enumeration `launch`] 170 171`launch` specifies whether control passes immediately into a 172newly-launched fiber. 173 174 enum class launch { 175 dispatch, 176 post 177 }; 178 179[heading `dispatch`] 180[variablelist 181[[Effects:] [A fiber launched with `launch == dispatch` is entered 182immediately. In other words, launching a fiber with `dispatch` suspends the 183caller (the previously-running fiber) until the fiber scheduler has a chance 184to resume it later.]] 185] 186 187[heading `post`] 188[variablelist 189[[Effects:] [A fiber launched with `launch == post` is passed to the 190fiber scheduler as ready, but it is not yet entered. The caller (the 191previously-running fiber) continues executing. The newly-launched fiber will 192be entered when the fiber scheduler has a chance to resume it later.]] 193[[Note:] [If `launch` is not explicitly specified, `post` is the default.]] 194] 195 196 197[#class_fiber] 198[section:fiber Class `fiber`] 199 200 #include <boost/fiber/fiber.hpp> 201 202 namespace boost { 203 namespace fibers { 204 205 class fiber { 206 public: 207 class id; 208 209 constexpr fiber() noexcept; 210 211 template< typename Fn, typename ... Args > 212 fiber( Fn &&, Args && ...); 213 214 template< typename Fn, typename ... Args > 215 fiber( ``[link class_launch `launch`]``, Fn &&, Args && ...); 216 217 template< typename __StackAllocator__, typename Fn, typename ... Args > 218 fiber( __allocator_arg_t__, StackAllocator &&, Fn &&, Args && ...); 219 220 template< typename __StackAllocator__, typename Fn, typename ... Args > 221 fiber( ``[link class_launch `launch`]``, __allocator_arg_t__, StackAllocator &&, Fn &&, Args && ...); 222 223 ~fiber(); 224 225 fiber( fiber const&) = delete; 226 227 fiber & operator=( fiber const&) = delete; 228 229 fiber( fiber &&) noexcept; 230 231 fiber & operator=( fiber &&) noexcept; 232 233 void swap( fiber &) noexcept; 234 235 bool joinable() const noexcept; 236 237 id get_id() const noexcept; 238 239 void detach(); 240 241 void join(); 242 243 template< typename PROPS > 244 PROPS & properties(); 245 }; 246 247 bool operator<( fiber const&, fiber const&) noexcept; 248 249 void swap( fiber &, fiber &) noexcept; 250 251 template< typename SchedAlgo, typename ... Args > 252 void use_scheduling_algorithm( Args && ...) noexcept; 253 254 bool has_ready_fibers() noexcept; 255 256 }} 257 258 259[heading Default constructor] 260 261 constexpr fiber() noexcept; 262 263[variablelist 264[[Effects:] [Constructs a __fiber__ instance that refers to __not_a_fiber__.]] 265[[Postconditions:] [`this->get_id() == fiber::id()`]] 266[[Throws:] [Nothing]] 267] 268 269[#fiber_fiber] 270[heading Constructor] 271 272 template< typename Fn, typename ... Args > 273 fiber( Fn && fn, Args && ... args); 274 275 template< typename Fn, typename ... Args > 276 fiber( ``[link class_launch `launch`]`` policy, Fn && fn, Args && ... args); 277 278 template< typename __StackAllocator__, typename Fn, typename ... Args > 279 fiber( __allocator_arg_t__, StackAllocator && salloc, Fn && fn, Args && ... args); 280 281 template< typename __StackAllocator__, typename Fn, typename ... Args > 282 fiber( ``[link class_launch `launch`]`` policy, __allocator_arg_t__, StackAllocator && salloc, 283 Fn && fn, Args && ... args); 284 285[variablelist 286[[Preconditions:] [`Fn` must be copyable or movable.]] 287[[Effects:] [`fn` is copied or moved into internal storage for access by the 288new fiber. If [class_link launch] is specified (or defaulted) to 289`post`, the new fiber is marked ["ready] and will be entered at the next 290opportunity. If `launch` is specified as `dispatch`, the calling fiber 291is suspended and the new fiber is entered immediately.]] 292[[Postconditions:] [`*this` refers to the newly created fiber of execution.]] 293[[Throws:] [__fiber_error__ if an error occurs.]] 294[[Note:] [__StackAllocator__ is required to allocate a stack for the internal 295__econtext__. If `StackAllocator` is not explicitly passed, the default stack 296allocator depends on `BOOST_USE_SEGMENTED_STACKS`: if defined, you will get a 297__segmented_stack__, else a __fixedsize_stack__.]] 298[[See also:] [__allocator_arg_t__, [link stack Stack allocation]]] 299] 300 301[heading Move constructor] 302 303 fiber( fiber && other) noexcept; 304 305[variablelist 306[[Effects:] [Transfers ownership of the fiber managed by `other` to the newly 307constructed __fiber__ instance.]] 308[[Postconditions:] [`other.get_id() == fiber::id()` and `get_id()` returns the 309value of `other.get_id()` prior to the construction]] 310[[Throws:] [Nothing]] 311] 312 313[heading Move assignment operator] 314 315 fiber & operator=( fiber && other) noexcept; 316 317[variablelist 318[[Effects:] [Transfers ownership of the fiber managed by `other` (if any) to 319`*this`.]] 320[[Postconditions:] [`other->get_id() == fiber::id()` and `get_id()` returns the 321value of `other.get_id()` prior to the assignment.]] 322[[Throws:] [Nothing]] 323] 324 325[heading Destructor] 326 327 ~fiber(); 328 329[variablelist 330[[Effects:] [If the fiber is __joinable__, calls std::terminate. Destroys 331`*this`.]] 332[[Note:] [The programmer must ensure that the destructor is never executed while 333the fiber is still __joinable__. Even if you know that the fiber has completed, 334you must still call either __join__ or __detach__ before destroying the `fiber` 335object.]] 336] 337 338[member_heading fiber..joinable] 339 340 bool joinable() const noexcept; 341 342[variablelist 343[[Returns:] [`true` if `*this` refers to a fiber of execution, which may or 344may not have completed; otherwise `false`.]] 345[[Throws:] [Nothing]] 346] 347 348[member_heading fiber..join] 349 350 void join(); 351 352[variablelist 353[[Preconditions:] [the fiber is __joinable__.]] 354[[Effects:] [Waits for the referenced fiber of execution to complete.]] 355[[Postconditions:] [The fiber of execution referenced on entry has completed. 356`*this` no longer refers to any fiber of execution.]] 357[[Throws:] [`fiber_error`]] 358[[Error Conditions:] [ 359[*resource_deadlock_would_occur]: if `this->get_id() == boost::this_fiber::get_id()`. 360[*invalid_argument]: if the fiber is not __joinable__.]] 361] 362 363[member_heading fiber..detach] 364 365 void detach(); 366 367[variablelist 368[[Preconditions:] [the fiber is __joinable__.]] 369[[Effects:] [The fiber of execution becomes detached, and no longer has an 370associated __fiber__ object.]] 371[[Postconditions:] [`*this` no longer refers to any fiber of execution.]] 372[[Throws:] [`fiber_error`]] 373[[Error Conditions:] [ 374[*invalid_argument]: if the fiber is not __joinable__.]] 375] 376 377[member_heading fiber..get_id] 378 379 fiber::id get_id() const noexcept; 380 381[variablelist 382[[Returns:] [If `*this` refers to a fiber of execution, an instance of 383__fiber_id__ that represents that fiber. Otherwise returns a 384default-constructed __fiber_id__.]] 385[[Throws:] [Nothing]] 386[[See also:] [[ns_function_link this_fiber..get_id]]] 387] 388 389[template_member_heading fiber..properties] 390 391 template< typename PROPS > 392 PROPS & properties(); 393 394[variablelist 395[[Preconditions:] [`*this` refers to a fiber of execution. [function_link 396use_scheduling_algorithm] has been called from this thread with a subclass of 397[template_link algorithm_with_properties] with the same template 398argument `PROPS`.]] 399[[Returns:] [a reference to the scheduler properties instance for `*this`.]] 400[[Throws:] [`std::bad_cast` if `use_scheduling_algorithm()` was called with a 401`algorithm_with_properties` subclass with some other template parameter 402than `PROPS`.]] 403[[Note:] [[template_link algorithm_with_properties] provides a way for a 404user-coded scheduler to associate extended properties, such as priority, with 405a fiber instance. This method allows access to those user-provided properties.]] 406[[See also:] [[link custom Customization]]] 407] 408 409[member_heading fiber..swap] 410 411 void swap( fiber & other) noexcept; 412 413[variablelist 414[[Effects:] [Exchanges the fiber of execution associated with `*this` and 415`other`, so `*this` becomes associated with the fiber formerly associated with 416`other`, and vice-versa.]] 417[[Postconditions:] [`this->get_id()` returns the same value as `other.get_id()` 418prior to the call. `other.get_id()` returns the same value as `this->get_id()` 419prior to the call.]] 420[[Throws:] [Nothing]] 421] 422 423[function_heading_for swap..fiber] 424 425 void swap( fiber & l, fiber & r) noexcept; 426 427[variablelist 428[[Effects:] [Same as `l.swap( r)`.]] 429[[Throws:] [Nothing]] 430] 431 432[function_heading operator<] 433 434 bool operator<( fiber const& l, fiber const& r) noexcept; 435 436[variablelist 437[[Returns:] [`true` if `l.get_id() < r.get_id()` is `true`, false otherwise.]] 438[[Throws:] [Nothing.]] 439] 440 441[function_heading use_scheduling_algorithm] 442 443 template< typename SchedAlgo, typename ... Args > 444 void use_scheduling_algorithm( Args && ... args) noexcept; 445 446[variablelist 447[[Effects:] [Directs __boost_fiber__ to use `SchedAlgo`, which must be a 448concrete subclass of __algo__, as the scheduling algorithm for all fibers in 449the current thread. Pass any required `SchedAlgo` constructor arguments as 450`args`.]] 451[[Note:] [If you want a given thread to use a non-default scheduling 452algorithm, make that thread call `use_scheduling_algorithm()` before any other 453__boost_fiber__ entry point. If no scheduler has been set for the current 454thread by the time __boost_fiber__ needs to use it, the library will 455create a default [class_link round_robin] instance for this thread.]] 456[[Throws:] [Nothing]] 457[[See also:] [[link scheduling Scheduling], [link custom Customization]]] 458] 459 460[function_heading has_ready_fibers] 461 462 bool has_ready_fibers() noexcept; 463 464[variablelist 465[[Returns:] [`true` if scheduler has fibers ready to run.]] 466[[Throws:] [Nothing]] 467[[Note:] [Can be used for work-stealing to find an idle scheduler.]] 468] 469 470[endsect] [/ section Class fiber] 471 472 473[#class_id] 474[section:id Class fiber::id] 475 476 #include <boost/fiber/fiber.hpp> 477 478 namespace boost { 479 namespace fibers { 480 481 class id { 482 public: 483 constexpr id() noexcept; 484 485 bool operator==( id const&) const noexcept; 486 487 bool operator!=( id const&) const noexcept; 488 489 bool operator<( id const&) const noexcept; 490 491 bool operator>( id const&) const noexcept; 492 493 bool operator<=( id const&) const noexcept; 494 495 bool operator>=( id const&) const noexcept; 496 497 template< typename charT, class traitsT > 498 friend std::basic_ostream< charT, traitsT > & 499 operator<<( std::basic_ostream< charT, traitsT > &, id const&); 500 }; 501 502 }} 503 504[heading Constructor] 505 506 constexpr id() noexcept; 507 508[variablelist 509[[Effects:] [Represents an instance of __not_a_fiber__.]] 510[[Throws:] [Nothing.]] 511] 512 513[operator_heading id..operator_equal..operator==] 514 515 bool operator==( id const& other) const noexcept; 516 517[variablelist 518[[Returns:] [`true` if `*this` and `other` represent the same fiber, 519or both represent __not_a_fiber__, `false` otherwise.]] 520[[Throws:] [Nothing.]] 521] 522 523[operator_heading id..operator_not_equal..operator!=] 524 525 bool operator!=( id const& other) const noexcept; 526 527[variablelist 528[[Returns:] [[`! (other == * this)]]] 529[[Throws:] [Nothing.]] 530] 531 532[operator_heading id..operator_less..operator<] 533 534 bool operator<( id const& other) const noexcept; 535 536[variablelist 537[[Returns:] [`true` if `*this != other` is true and the 538implementation-defined total order of `fiber::id` values places `*this` before 539`other`, false otherwise.]] 540[[Throws:] [Nothing.]] 541] 542 543[operator_heading id..operator_greater..operator>] 544 545 bool operator>( id const& other) const noexcept; 546 547[variablelist 548[[Returns:] [`other < * this`]] 549[[Throws:] [Nothing.]] 550] 551 552[operator_heading id..operator_less_equal..operator<=] 553 554 bool operator<=( id const& other) const noexcept; 555 556[variablelist 557[[Returns:] [`! (other < * this)`]] 558[[Throws:] [Nothing.]] 559] 560 561[operator_heading id..operator_greater_equal..operator>=] 562 563 bool operator>=( id const& other) const noexcept; 564 565[variablelist 566[[Returns:] [`! (* this < other)`]] 567[[Throws:] [Nothing.]] 568] 569 570[heading operator<<] 571 572 template< typename charT, class traitsT > 573 std::basic_ostream< charT, traitsT > & 574 operator<<( std::basic_ostream< charT, traitsT > & os, id const& other); 575 576[variablelist 577[[Efects:] [Writes the representation of `other` to stream `os`. The 578representation is unspecified.]] 579[[Returns:] [`os`]] 580] 581 582 583[endsect] [/ section Class fiber::id] 584 585 586[section:this_fiber Namespace this_fiber] 587 588In general, `this_fiber` operations may be called from the ["main] fiber 589[mdash] the fiber on which function `main()` is entered [mdash] as well as 590from an explicitly-launched thread[s] thread-function. That is, in many 591respects the main fiber on each thread can be treated like an 592explicitly-launched fiber. 593 594 595 namespace boost { 596 namespace this_fiber { 597 598 fibers::fiber::id get_id() noexcept; 599 void yield() noexcept; 600 template< typename Clock, typename Duration > 601 void sleep_until( std::chrono::time_point< Clock, Duration > const&); 602 template< typename Rep, typename Period > 603 void sleep_for( std::chrono::duration< Rep, Period > const&); 604 template< typename PROPS > 605 PROPS & properties(); 606 607 }} 608 609[ns_function_heading this_fiber..get_id] 610 611 #include <boost/fiber/operations.hpp> 612 613 namespace boost { 614 namespace fibers { 615 616 fiber::id get_id() noexcept; 617 618 }} 619 620[variablelist 621[[Returns:] [An instance of __fiber_id__ that represents the currently 622executing fiber.]] 623[[Throws:] [Nothing.]] 624] 625 626[ns_function_heading this_fiber..sleep_until] 627 628 #include <boost/fiber/operations.hpp> 629 630 namespace boost { 631 namespace fibers { 632 633 template< typename Clock, typename Duration > 634 void sleep_until( std::chrono::time_point< Clock, Duration > const& abs_time); 635 636 }} 637 638[variablelist 639[[Effects:] [Suspends the current fiber until the time point specified by 640`abs_time` has been reached.]] 641[[Throws:] [timeout-related exceptions.]] 642[[Note:] [The current fiber will not resume before `abs_time`, but there are no 643guarantees about how soon after `abs_time` it might resume.]] 644[[Note:] [["timeout-related exceptions] are as defined in the C++ Standard, 645section [*30.2.4 Timing specifications \[thread.req.timing\]]: ["A function 646that takes an argument which specifies a timeout will throw if, during its 647execution, a clock, time point, or time duration throws an exception. Such 648exceptions are referred to as ['timeout-related exceptions.]]]] 649] 650 651[ns_function_heading this_fiber..sleep_for] 652 653 #include <boost/fiber/operations.hpp> 654 655 namespace boost { 656 namespace fibers { 657 658 template< class Rep, class Period > 659 void sleep_for( std::chrono::duration< Rep, Period > const& rel_time); 660 661 }} 662 663[variablelist 664[[Effects:] [Suspends the current fiber until the time duration specified by 665`rel_time` has elapsed.]] 666[[Throws:] [timeout-related exceptions.]] 667[[Note:][The current fiber will not resume before `rel_time` has elapsed, but 668there are no guarantees about how soon after that it might resume.]] 669] 670 671[ns_function_heading this_fiber..yield] 672 673 #include <boost/fiber/operations.hpp> 674 675 namespace boost { 676 namespace fibers { 677 678 void yield() noexcept; 679 680 }} 681 682[variablelist 683[[Effects:] [Relinquishes execution control, allowing other fibers to run.]] 684[[Throws:] [Nothing.]] 685[[Note:] [A fiber that calls 686`yield()` is not suspended: it is immediately passed to the scheduler as ready 687to run.]] 688] 689 690[ns_function_heading this_fiber..properties] 691 692 #include <boost/fiber/operations.hpp> 693 694 namespace boost { 695 namespace fibers { 696 697 template< typename PROPS > 698 PROPS & properties(); 699 700 }} 701 702[variablelist 703[[Preconditions:] [[function_link use_scheduling_algorithm] has been called 704from this thread with a subclass of [template_link 705algorithm_with_properties] with the same template argument `PROPS`.]] 706[[Returns:] [a reference to the scheduler properties instance for the 707currently running fiber.]] 708[[Throws:] [`std::bad_cast` if `use_scheduling_algorithm()` was called with an 709`algorithm_with_properties` subclass with some other template parameter 710than `PROPS`.]] 711[[Note:] [[template_link algorithm_with_properties] provides a way for a 712user-coded scheduler to associate extended properties, such as priority, with 713a fiber instance. This function allows access to those user-provided 714properties.]] 715[[Note:] [The first time this function is called from the main fiber of a 716thread, it may internally yield, permitting other fibers to run.]] 717[[See also:] [[link custom Customization]]] 718] 719 720 721[endsect] [/ section Namespace this_fiber] 722 723 724[endsect] [/ section Fiber Management] 725