• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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