• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1[/
2          Copyright Oliver Kowalke 2013.
3 Distributed under the Boost Software License, Version 1.0.
4    (See accompanying file LICENSE_1_0.txt or copy at
5          http://www.boost.org/LICENSE_1_0.txt
6]
7
8[#scheduling]
9[section:scheduling Scheduling]
10
11The fibers in a thread are coordinated by a fiber manager. Fibers trade
12control cooperatively, rather than preemptively: the currently-running fiber
13retains control until it invokes some operation that passes control to the
14manager. Each time a fiber suspends (or yields), the fiber manager consults a
15scheduler to determine which fiber will run next.
16
17__boost_fiber__ provides the fiber manager, but the scheduler is a
18customization point. (See [link custom Customization].)
19
20Each thread has its own scheduler. Different threads in a process may use
21different schedulers. By default, __boost_fiber__ implicitly instantiates
22[class_link round_robin] as the scheduler for each thread.
23
24You are explicitly permitted to code your own __algo__ subclass. For the most
25part, your `algorithm` subclass need not defend against cross-thread
26calls: the fiber manager intercepts and defers such calls. Most
27`algorithm` methods are only ever directly called from the thread whose
28fibers it is managing [mdash] with exceptions as documented below.
29
30Your `algorithm` subclass is engaged on a particular thread by calling
31[function_link use_scheduling_algorithm]:
32
33        void thread_fn() {
34            boost::fibers::use_scheduling_algorithm< my_fiber_scheduler >();
35            ...
36        }
37
38A scheduler class must implement interface __algo__. __boost_fiber__ provides
39schedulers: __round_robin__, __work_stealing__, __numa_work_stealing__ and
40__shared_work__.
41
42        void thread( std::uint32_t thread_count) {
43            // thread registers itself at work-stealing scheduler
44            boost::fibers::use_scheduling_algorithm< boost::fibers::algo::work_stealing >( thread_count);
45            ...
46        }
47
48        // count of logical cpus
49        std::uint32_t thread_count = std::thread::hardware_concurrency();
50        // start worker-threads first
51        std::vector< std::thread > threads;
52        for ( std::uint32_t i = 1 /* count start-thread */; i < thread_count; ++i) {
53            // spawn thread
54            threads.emplace_back( thread, thread_count);
55        }
56        // start-thread registers itself at work-stealing scheduler
57        boost::fibers::use_scheduling_algorithm< boost::fibers::algo::work_stealing >( thread_count);
58        ...
59
60The example spawns as many threads as `std::thread::hardware_concurrency()`
61returns.
62Each thread runs a __work_stealing__ scheduler. Each instance of this
63scheduler needs to know how many threads run the work-stealing scheduler in the
64program.
65If the local queue of one thread runs out of ready fibers, the thread tries to
66steal a ready fiber from another thread running this scheduler.
67
68
69[class_heading algorithm]
70
71`algorithm` is the abstract base class defining the interface that a
72fiber scheduler must implement.
73
74        #include <boost/fiber/algo/algorithm.hpp>
75
76        namespace boost {
77        namespace fibers {
78        namespace algo {
79
80        struct algorithm {
81            virtual ~algorithm();
82
83            virtual void awakened( context *) noexcept = 0;
84
85            virtual context * pick_next() noexcept = 0;
86
87            virtual bool has_ready_fibers() const noexcept = 0;
88
89            virtual void suspend_until( std::chrono::steady_clock::time_point const&) noexcept = 0;
90
91            virtual void notify() noexcept = 0;
92        };
93
94        }}}
95
96[member_heading algorithm..awakened]
97
98        virtual void awakened( context * f) noexcept = 0;
99
100[variablelist
101[[Effects:] [Informs the scheduler that fiber `f` is ready to run. Fiber `f`
102might be newly launched, or it might have been blocked but has just been
103awakened, or it might have called [ns_function_link this_fiber..yield].]]
104[[Note:] [This method advises the scheduler to add fiber `f` to its collection
105of fibers ready to run. A typical scheduler implementation places `f` into a
106queue.]]
107[[See also:] [[class_link round_robin]]]
108]
109
110[member_heading algorithm..pick_next]
111
112        virtual context * pick_next() noexcept = 0;
113
114[variablelist
115[[Returns:] [the fiber which is to be resumed next, or `nullptr` if there is no
116ready fiber.]]
117[[Note:] [This is where the scheduler actually specifies the fiber which is to
118run next. A typical scheduler implementation chooses the head of the ready
119queue.]]
120[[See also:] [[class_link round_robin]]]
121]
122
123[member_heading algorithm..has_ready_fibers]
124
125        virtual bool has_ready_fibers() const noexcept = 0;
126
127[variablelist
128[[Returns:] [`true` if scheduler has fibers ready to run.]]
129]
130
131[member_heading algorithm..suspend_until]
132
133        virtual void suspend_until( std::chrono::steady_clock::time_point const& abs_time) noexcept = 0;
134
135[variablelist
136[[Effects:] [Informs the scheduler that no fiber will be ready until
137time-point `abs_time`.]]
138[[Note:] [This method allows a custom scheduler to yield control to the
139containing environment in whatever way makes sense. The fiber manager is
140stating that `suspend_until()` need not return until `abs_time` [mdash] or
141[member_link algorithm..notify] is called [mdash] whichever comes first.
142The interaction with `notify()` means that, for instance, calling
143[@http://en.cppreference.com/w/cpp/thread/sleep_until
144`std::this_thread::sleep_until(abs_time)`] would be too simplistic.
145[member_link round_robin..suspend_until] uses a
146[@http://en.cppreference.com/w/cpp/thread/condition_variable
147`std::condition_variable`] to coordinate with [member_link
148round_robin..notify].]]
149[[Note:] [Given that `notify()` might be called from another thread, your
150`suspend_until()` implementation [mdash] like the rest of your
151`algorithm` implementation [mdash] must guard any data it shares with
152your `notify()` implementation.]]
153]
154
155[member_heading algorithm..notify]
156
157        virtual void notify() noexcept = 0;
158
159[variablelist
160[[Effects:] [Requests the scheduler to return from a pending call to
161[member_link algorithm..suspend_until].]]
162[[Note:] [Alone among the `algorithm` methods, `notify()` may be called
163from another thread. Your `notify()` implementation must guard any data it
164shares with the rest of your `algorithm` implementation.]]
165]
166
167[class_heading round_robin]
168
169This class implements __algo__, scheduling fibers in round-robin fashion.
170
171        #include <boost/fiber/algo/round_robin.hpp>
172
173        namespace boost {
174        namespace fibers {
175        namespace algo {
176
177        class round_robin : public algorithm {
178            virtual void awakened( context *) noexcept;
179
180            virtual context * pick_next() noexcept;
181
182            virtual bool has_ready_fibers() const noexcept;
183
184            virtual void suspend_until( std::chrono::steady_clock::time_point const&) noexcept;
185
186            virtual void notify() noexcept;
187        };
188
189        }}}
190
191[member_heading round_robin..awakened]
192
193        virtual void awakened( context * f) noexcept;
194
195[variablelist
196[[Effects:] [Enqueues fiber `f` onto a ready queue.]]
197[[Throws:] [Nothing.]]
198]
199
200[member_heading round_robin..pick_next]
201
202        virtual context * pick_next() noexcept;
203
204[variablelist
205[[Returns:] [the fiber at the head of the ready queue, or `nullptr` if the
206queue is empty.]]
207[[Throws:] [Nothing.]]
208[[Note:] [Placing ready fibers onto the tail of a queue, and returning them
209from the head of that queue, shares the thread between ready fibers in
210round-robin fashion.]]
211]
212
213[member_heading round_robin..has_ready_fibers]
214
215        virtual bool has_ready_fibers() const noexcept;
216
217[variablelist
218[[Returns:] [`true` if scheduler has fibers ready to run.]]
219[[Throws:] [Nothing.]]
220]
221
222[member_heading round_robin..suspend_until]
223
224        virtual void suspend_until( std::chrono::steady_clock::time_point const& abs_time) noexcept;
225
226[variablelist
227[[Effects:] [Informs `round_robin` that no ready fiber will be available until
228time-point `abs_time`. This implementation blocks in
229[@http://en.cppreference.com/w/cpp/thread/condition_variable/wait_until
230`std::condition_variable::wait_until()`].]]
231[[Throws:] [Nothing.]]
232]
233
234[member_heading round_robin..notify]
235
236        virtual void notify() noexcept = 0;
237
238[variablelist
239[[Effects:] [Wake up a pending call to [member_link
240round_robin..suspend_until], some fibers might be ready. This implementation
241wakes `suspend_until()` via
242[@http://en.cppreference.com/w/cpp/thread/condition_variable/notify_all
243`std::condition_variable::notify_all()`].]]
244[[Throws:] [Nothing.]]
245]
246
247
248
249[class_heading work_stealing]
250
251This class implements __algo__; if the local ready-queue runs out of ready fibers, ready fibers are stolen
252from other schedulers.[br]
253The victim scheduler (from which a ready fiber is stolen) is selected at random.
254
255[note Worker-threads are stored in a static variable, dynamically adding/removing worker threads is not supported.]
256
257        #include <boost/fiber/algo/work_stealing.hpp>
258
259        namespace boost {
260        namespace fibers {
261        namespace algo {
262
263        class work_stealing : public algorithm {
264        public:
265            work_stealing( std::uint32_t thread_count, bool suspend = false);
266
267            work_stealing( work_stealing const&) = delete;
268            work_stealing( work_stealing &&) = delete;
269
270            work_stealing & operator=( work_stealing const&) = delete;
271            work_stealing & operator=( work_stealing &&) = delete;
272
273            virtual void awakened( context *) noexcept;
274
275            virtual context * pick_next() noexcept;
276
277            virtual bool has_ready_fibers() const noexcept;
278
279            virtual void suspend_until( std::chrono::steady_clock::time_point const&) noexcept;
280
281            virtual void notify() noexcept;
282        };
283
284        }}}
285
286[heading Constructor]
287
288        work_stealing( std::uint32_t thread_count, bool suspend = false);
289
290[variablelist
291[[Effects:] [Constructs work-stealing scheduling algorithm. `thread_count` represents the number of threads
292running this algorithm.]]
293[[Throws:] [`system_error`]]
294[[Note:][If `suspend` is set to `true`, then the scheduler suspends if no ready fiber could be stolen.
295The scheduler will by woken up if a sleeping fiber times out or it was notified from remote (other thread or
296fiber scheduler).]]
297]
298
299[member_heading work_stealing..awakened]
300
301        virtual void awakened( context * f) noexcept;
302
303[variablelist
304[[Effects:] [Enqueues fiber `f` onto the shared ready queue.]]
305[[Throws:] [Nothing.]]
306]
307
308[member_heading work_stealing..pick_next]
309
310        virtual context * pick_next() noexcept;
311
312[variablelist
313[[Returns:] [the fiber at the head of the ready queue, or `nullptr` if the
314queue is empty.]]
315[[Throws:] [Nothing.]]
316[[Note:] [Placing ready fibers onto the tail of the sahred queue, and returning them
317from the head of that queue, shares the thread between ready fibers in
318round-robin fashion.]]
319]
320
321[member_heading work_stealing..has_ready_fibers]
322
323        virtual bool has_ready_fibers() const noexcept;
324
325[variablelist
326[[Returns:] [`true` if scheduler has fibers ready to run.]]
327[[Throws:] [Nothing.]]
328]
329
330[member_heading work_stealing..suspend_until]
331
332        virtual void suspend_until( std::chrono::steady_clock::time_point const& abs_time) noexcept;
333
334[variablelist
335[[Effects:] [Informs `work_stealing` that no ready fiber will be available until
336time-point `abs_time`. This implementation blocks in
337[@http://en.cppreference.com/w/cpp/thread/condition_variable/wait_until
338`std::condition_variable::wait_until()`].]]
339[[Throws:] [Nothing.]]
340]
341
342[member_heading work_stealing..notify]
343
344        virtual void notify() noexcept = 0;
345
346[variablelist
347[[Effects:] [Wake up a pending call to [member_link
348work_stealing..suspend_until], some fibers might be ready. This implementation
349wakes `suspend_until()` via
350[@http://en.cppreference.com/w/cpp/thread/condition_variable/notify_all
351`std::condition_variable::notify_all()`].]]
352[[Throws:] [Nothing.]]
353]
354
355
356[class_heading shared_work]
357
358[note Because of the non-locality of data, ['shared_work] is less performant
359than __work_stealing__.]
360
361This class implements __algo__, scheduling fibers in round-robin fashion.
362Ready fibers are shared between all instances (running on different threads)
363of shared_work, thus the work is distributed equally over all threads.
364
365[note Worker-threads are stored in a static variable, dynamically adding/removing worker threads is not supported.]
366
367        #include <boost/fiber/algo/shared_work.hpp>
368
369        namespace boost {
370        namespace fibers {
371        namespace algo {
372
373        class shared_work : public algorithm {
374            shared_work();
375            shared_work( bool suspend);
376
377            virtual void awakened( context *) noexcept;
378
379            virtual context * pick_next() noexcept;
380
381            virtual bool has_ready_fibers() const noexcept;
382
383            virtual void suspend_until( std::chrono::steady_clock::time_point const&) noexcept;
384
385            virtual void notify() noexcept;
386        };
387
388        }}}
389
390[heading Constructor]
391
392        shared_work();
393        shared_work( bool suspend);
394
395[variablelist
396[[Effects:] [Constructs work-sharing scheduling algorithm.]]
397[[Throws:] [`system_error`]]
398[[Note:][If `suspend` is set to `true` (default is `false`), then the scheduler suspends if no ready fiber
399could be stolen. The scheduler will by woken up if a sleeping fiber times out or it was notified from remote
400(other thread or fiber scheduler).]]
401]
402
403[member_heading shared_work..awakened]
404
405        virtual void awakened( context * f) noexcept;
406
407[variablelist
408[[Effects:] [Enqueues fiber `f` onto the shared ready queue.]]
409[[Throws:] [Nothing.]]
410]
411
412[member_heading shared_work..pick_next]
413
414        virtual context * pick_next() noexcept;
415
416[variablelist
417[[Returns:] [the fiber at the head of the ready queue, or `nullptr` if the
418queue is empty.]]
419[[Throws:] [Nothing.]]
420[[Note:] [Placing ready fibers onto the tail of the shared queue, and returning them
421from the head of that queue, shares the thread between ready fibers in
422round-robin fashion.]]
423]
424
425[member_heading shared_work..has_ready_fibers]
426
427        virtual bool has_ready_fibers() const noexcept;
428
429[variablelist
430[[Returns:] [`true` if scheduler has fibers ready to run.]]
431[[Throws:] [Nothing.]]
432]
433
434[member_heading shared_work..suspend_until]
435
436        virtual void suspend_until( std::chrono::steady_clock::time_point const& abs_time) noexcept;
437
438[variablelist
439[[Effects:] [Informs `shared_work` that no ready fiber will be available until
440time-point `abs_time`. This implementation blocks in
441[@http://en.cppreference.com/w/cpp/thread/condition_variable/wait_until
442`std::condition_variable::wait_until()`].]]
443[[Throws:] [Nothing.]]
444]
445
446[member_heading shared_work..notify]
447
448        virtual void notify() noexcept = 0;
449
450[variablelist
451[[Effects:] [Wake up a pending call to [member_link
452shared_work..suspend_until], some fibers might be ready. This implementation
453wakes `suspend_until()` via
454[@http://en.cppreference.com/w/cpp/thread/condition_variable/notify_all
455`std::condition_variable::notify_all()`].]]
456[[Throws:] [Nothing.]]
457]
458
459
460[heading Custom Scheduler Fiber Properties]
461
462A scheduler class directly derived from __algo__ can use any information
463available from [class_link context] to implement the `algorithm`
464interface. But a custom scheduler might need to track additional properties
465for a fiber. For instance, a priority-based scheduler would need to track a
466fiber[s] priority.
467
468__boost_fiber__ provides a mechanism by which your custom scheduler can
469associate custom properties with each fiber.
470
471[class_heading fiber_properties]
472
473A custom fiber properties class must be derived from `fiber_properties`.
474
475        #include <boost/fiber/properties.hpp>
476
477        namespace boost {
478        namespace fibers {
479
480        class fiber_properties {
481        public:
482            fiber_properties( context *) noexcept;
483
484            virtual ~fiber_properties();
485
486        protected:
487            void notify() noexcept;
488        };
489
490        }}
491
492[heading Constructor]
493
494        fiber_properties( context * f) noexcept;
495
496[variablelist
497[[Effects:] [Constructs base-class component of custom subclass.]]
498[[Throws:] [Nothing.]]
499[[Note:] [Your subclass constructor must accept a `context*` and pass it
500to the base-class `fiber_properties` constructor.]]
501]
502
503[member_heading fiber_properties..notify]
504
505        void notify() noexcept;
506
507[variablelist
508[[Effects:] [Pass control to the custom [template_link
509algorithm_with_properties] subclass[s] [member_link
510algorithm_with_properties..property_change] method.]]
511[[Throws:] [Nothing.]]
512[[Note:] [A custom scheduler[s] [member_link
513algorithm_with_properties..pick_next] method might dynamically select
514from the ready fibers, or [member_link
515algorithm_with_properties..awakened] might instead insert each ready
516fiber into some form of ready queue for `pick_next()`. In the latter case, if
517application code modifies a fiber property (e.g. priority) that should affect
518that fiber[s] relationship to other ready fibers, the custom scheduler must be
519given the opportunity to reorder its ready queue. The custom property subclass
520should implement an access method to modify such a property; that access
521method should call `notify()` once the new property value has been stored.
522This passes control to the custom scheduler[s] `property_change()` method,
523allowing the custom scheduler to reorder its ready queue appropriately. Use at
524your discretion. Of course, if you define a property which does not affect the
525behavior of the `pick_next()` method, you need not call `notify()` when that
526property is modified.]]
527]
528
529[template_heading algorithm_with_properties]
530
531A custom scheduler that depends on a custom properties class `PROPS` should be
532derived from `algorithm_with_properties<PROPS>`. `PROPS` should be
533derived from [class_link fiber_properties].
534
535        #include <boost/fiber/algorithm.hpp>
536
537        namespace boost {
538        namespace fibers {
539        namespace algo {
540
541        template< typename PROPS >
542        struct algorithm_with_properties {
543            virtual void awakened( context *, PROPS &) noexcept = 0;
544
545            virtual context * pick_next() noexcept;
546
547            virtual bool has_ready_fibers() const noexcept;
548
549            virtual void suspend_until( std::chrono::steady_clock::time_point const&) noexcept = 0;
550
551            virtual void notify() noexcept = 0;
552
553            PROPS & properties( context *) noexcept;
554
555            virtual void property_change( context *, PROPS &) noexcept;
556
557            virtual fiber_properties * new_properties( context *);
558        };
559
560        }}}
561
562[member_heading algorithm_with_properties..awakened]
563
564        virtual void awakened( context * f, PROPS & properties) noexcept;
565
566[variablelist
567[[Effects:] [Informs the scheduler that fiber `f` is ready to run, like
568[member_link algorithm..awakened]. Passes the fiber[s] associated `PROPS`
569instance.]]
570[[Throws:] [Nothing.]]
571[[Note:] [An `algorithm_with_properties<>` subclass must override this
572method instead of `algorithm::awakened()`.]]
573]
574
575[member_heading algorithm_with_properties..pick_next]
576
577        virtual context * pick_next() noexcept;
578
579[variablelist
580[[Returns:] [the fiber which is to be resumed next, or `nullptr` if there is no
581ready fiber.]]
582[[Throws:] [Nothing.]]
583[[Note:] [same as [member_link algorithm..pick_next]]]
584]
585
586[member_heading algorithm_with_properties..has_ready_fibers]
587
588        virtual bool has_ready_fibers() const noexcept;
589
590[variablelist
591[[Returns:] [`true` if scheduler has fibers ready to run.]]
592[[Throws:] [Nothing.]]
593[[Note:] [same as [member_link algorithm..has_ready_fibers]]]
594]
595
596[member_heading algorithm_with_properties..suspend_until]
597
598        virtual void suspend_until( std::chrono::steady_clock::time_point const& abs_time) noexcept = 0;
599
600[variablelist
601[[Effects:] [Informs the scheduler that no fiber will be ready until
602time-point `abs_time`.]]
603[[Note:] [same as [member_link algorithm..suspend_until]]]
604]
605
606[member_heading algorithm_with_properties..notify]
607
608        virtual void notify() noexcept = 0;
609
610[variablelist
611[[Effects:] [Requests the scheduler to return from a pending call to
612[member_link algorithm_with_properties..suspend_until].]]
613[[Note:] [same as [member_link algorithm..notify]]]
614]
615
616[member_heading algorithm_with_properties..properties]
617
618        PROPS& properties( context * f) noexcept;
619
620[variablelist
621[[Returns:] [the `PROPS` instance associated with fiber `f`.]]
622[[Throws:] [Nothing.]]
623[[Note:] [The fiber[s] associated `PROPS` instance is already passed to
624[member_link algorithm_with_properties..awakened] and [member_link
625algorithm_with_properties..property_change]. However, every [class_link
626algorithm] subclass is expected to track a collection of ready
627[class_link context] instances. This method allows your custom scheduler
628to retrieve the [class_link fiber_properties] subclass instance for any
629`context` in its collection.]]
630]
631
632[member_heading algorithm_with_properties..property_change]
633
634        virtual void property_change( context * f, PROPS & properties) noexcept;
635
636[variablelist
637[[Effects:] [Notify the custom scheduler of a possibly-relevant change to a
638property belonging to fiber `f`. `properties` contains the new values of
639all relevant properties.]]
640[[Throws:] [Nothing.]]
641[[Note:] [This method is only called when a custom [class_link
642fiber_properties] subclass explicitly calls [member_link
643fiber_properties..notify].]]
644]
645
646[member_heading algorithm_with_properties..new_properties]
647
648        virtual fiber_properties * new_properties( context * f);
649
650[variablelist
651[[Returns:] [A new instance of [class_link fiber_properties] subclass
652`PROPS`.]]
653[[Note:] [By default, `algorithm_with_properties<>::new_properties()`
654simply returns `new PROPS(f)`, placing the `PROPS` instance on the heap.
655Override this method to allocate `PROPS` some other way. The returned
656`fiber_properties` pointer must point to the `PROPS` instance to be associated
657with fiber `f`.]]
658]
659
660[#context]
661[class_heading context]
662
663While you are free to treat `context*` as an opaque token, certain
664`context` members may be useful to a custom scheduler implementation.
665
666[#ready_queue_t]
667Of particular note is the fact that `context` contains a hook to participate
668in a [@http://www.boost.org/doc/libs/release/doc/html/intrusive/list.html
669`boost::intrusive::list`] [^typedef][,]ed as
670`boost::fibers::scheduler::ready_queue_t`. This hook is reserved for use by
671[class_link algorithm] implementations. (For instance, [class_link
672round_robin] contains a `ready_queue_t` instance to manage its ready fibers.)
673See [member_link context..ready_is_linked], [member_link context..ready_link],
674[member_link context..ready_unlink].
675
676Your `algorithm` implementation may use any container you desire to
677manage passed `context` instances. `ready_queue_t` avoids some of the overhead
678of typical STL containers.
679
680        #include <boost/fiber/context.hpp>
681
682        namespace boost {
683        namespace fibers {
684
685        enum class type {
686          none               = ``['unspecified]``,
687          main_context       = ``['unspecified]``, // fiber associated with thread's stack
688          dispatcher_context = ``['unspecified]``, // special fiber for maintenance operations
689          worker_context     = ``['unspecified]``, // fiber not special to the library
690          pinned_context     = ``['unspecified]``  // fiber must not be migrated to another thread
691        };
692
693        class context {
694        public:
695            class id;
696
697            static context * active() noexcept;
698
699            context( context const&) = delete;
700            context & operator=( context const&) = delete;
701
702            id get_id() const noexcept;
703
704            void detach() noexcept;
705            void attach( context *) noexcept;
706
707            bool is_context( type) const noexcept;
708
709            bool is_terminated() const noexcept;
710
711            bool ready_is_linked() const noexcept;
712            bool remote_ready_is_linked() const noexcept;
713            bool wait_is_linked() const noexcept;
714
715            template< typename List >
716            void ready_link( List &) noexcept;
717            template< typename List >
718            void remote_ready_link( List &) noexcept;
719            template< typename List >
720            void wait_link( List &) noexcept;
721
722            void ready_unlink() noexcept;
723            void remote_ready_unlink() noexcept;
724            void wait_unlink() noexcept;
725
726            void suspend() noexcept;
727            void schedule( context *) noexcept;
728        };
729
730        bool operator<( context const& l, context const& r) noexcept;
731
732        }}
733
734[static_member_heading context..active]
735
736        static context * active() noexcept;
737
738[variablelist
739[[Returns:] [Pointer to instance of current fiber.]]
740[[Throws:] [Nothing]]
741]
742
743[member_heading context..get_id]
744
745        context::id get_id() const noexcept;
746
747[variablelist
748[[Returns:] [If `*this` refers to a fiber of execution, an instance of
749__fiber_id__ that represents that fiber. Otherwise returns a
750default-constructed __fiber_id__.]]
751[[Throws:] [Nothing]]
752[[See also:] [[member_link fiber..get_id]]]
753]
754
755[member_heading context..attach]
756
757        void attach( context * f) noexcept;
758
759[variablelist
760[[Precondition:] [`this->get_scheduler() == nullptr`]]
761[[Effects:] [Attach fiber `f` to scheduler running `*this`.]]
762[[Postcondition:] [`this->get_scheduler() != nullptr`]]
763[[Throws:] [Nothing]]
764[[Note:] [A typical call: `boost::fibers::context::active()->attach(f);`]]
765[[Note:] [`f` must not be the running fiber[s] context. It must not be
766__blocked__ or terminated. It must not be a `pinned_context`. It must be
767currently detached. It must not currently be linked into an [class_link
768algorithm] implementation[s] ready queue. Most of these conditions are
769implied by `f` being owned by an `algorithm` implementation: that is, it
770has been passed to [member_link algorithm..awakened] but has not yet
771been returned by [member_link algorithm..pick_next]. Typically a
772`pick_next()` implementation would call `attach()` with the `context*` it is
773about to return. It must first remove `f` from its ready queue. You should
774never pass a `pinned_context` to `attach()` because you should never have
775called its `detach()` method in the first place.]]
776]
777
778[member_heading context..detach]
779
780        void detach() noexcept;
781
782[variablelist
783[[Precondition:] [`(this->get_scheduler() != nullptr) && ! this->is_context(pinned_context)`]]
784[[Effects:] [Detach fiber `*this` from its scheduler running `*this`.]]
785[[Throws:] [Nothing]]
786[[Postcondition:] [`this->get_scheduler() == nullptr`]]
787[[Note:] [This method must be called on the thread with which the fiber is
788currently associated. `*this` must not be the running fiber[s] context. It
789must not be __blocked__ or terminated. It must not be a `pinned_context`. It
790must not be detached already. It must not already be linked into an [class_link
791algorithm] implementation[s] ready queue. Most of these conditions are
792implied by `*this` being passed to [member_link algorithm..awakened]; an
793`awakened()` implementation must, however, test for `pinned_context`. It must
794call `detach()` ['before] linking `*this` into its ready queue.]]
795[[Note:] [In particular, it is erroneous to attempt to migrate a fiber from
796one thread to another by calling both `detach()` and `attach()` in the
797[member_link algorithm..pick_next] method. `pick_next()` is called on
798the intended destination thread. `detach()` must be called on the fiber[s]
799original thread. You must call `detach()` in the corresponding `awakened()`
800method.]]
801[[Note:] [Unless you intend make a fiber available for potential migration to
802a different thread, you should call neither `detach()` nor `attach()` with its
803`context`.]]
804]
805
806[member_heading context..is_context]
807
808        bool is_context( type t) const noexcept;
809
810[variablelist
811[[Returns:] [`true` if `*this` is of the specified type.]]
812[[Throws:] [Nothing]]
813[[Note:] [`type::worker_context` here means any fiber not special to the
814library. For `type::main_context` the `context` is associated with the ["main]
815fiber of the thread: the one implicitly created by the thread itself, rather
816than one explicitly created by __boost_fiber__. For `type::dispatcher_context`
817the `context` is associated with a ["dispatching] fiber, responsible for
818dispatching awakened fibers to a scheduler[s] ready-queue. The ["dispatching]
819fiber is an implementation detail of the fiber manager. The context of the
820["main] or ["dispatching] fiber [mdash] any fiber for which
821`is_context(pinned_context)` is `true` [mdash] must never be passed to
822[member_link context..detach].]]
823]
824
825[member_heading context..is_terminated]
826
827        bool is_terminated() const noexcept;
828
829[variablelist
830[[Returns:] [`true` if `*this` is no longer a valid context.]]
831[[Throws:] [Nothing]]
832[[Note:] [The `context` has returned from its fiber-function and is
833no longer considered a valid context.]]
834]
835
836[member_heading context..ready_is_linked]
837
838        bool ready_is_linked() const noexcept;
839
840[variablelist
841[[Returns:] [`true` if `*this` is stored in an [class_link algorithm]
842implementation[s] ready-queue.]]
843[[Throws:] [Nothing]]
844[[Note:] [Specifically, this method indicates whether [member_link
845context..ready_link] has been called on `*this`. `ready_is_linked()` has
846no information about participation in any other containers.]]
847]
848
849[member_heading context..remote_ready_is_linked]
850
851        bool remote_ready_is_linked() const noexcept;
852
853[variablelist
854[[Returns:] [`true` if `*this` is stored in the fiber manager[s]
855remote-ready-queue.]]
856[[Throws:] [Nothing]]
857[[Note:] [A `context` signaled as ready by another thread is first stored in
858the fiber manager[s] remote-ready-queue. This is the mechanism by which the
859fiber manager protects an [class_link algorithm] implementation from
860cross-thread [member_link algorithm..awakened] calls.]]
861]
862
863[member_heading context..wait_is_linked]
864
865        bool wait_is_linked() const noexcept;
866
867[variablelist
868[[Returns:] [`true` if `*this` is stored in the wait-queue of some
869synchronization object.]]
870[[Throws:] [Nothing]]
871[[Note:] [The `context` of a fiber waiting on a synchronization object (e.g.
872`mutex`, `condition_variable` etc.) is stored in the wait-queue of that
873synchronization object.]]
874]
875
876[member_heading context..ready_link]
877
878        template< typename List >
879        void ready_link( List & lst) noexcept;
880
881[variablelist
882[[Effects:] [Stores `*this` in ready-queue `lst`.]]
883[[Throws:] [Nothing]]
884[[Note:] [Argument `lst` must be a doubly-linked list from
885__boost_intrusive__, e.g. an instance of
886`boost::fibers::scheduler::ready_queue_t`. Specifically, it must be a
887[@http://www.boost.org/doc/libs/release/doc/html/intrusive/list.html
888`boost::intrusive::list`] compatible with the `list_member_hook` stored in the
889`context` object.]]
890]
891
892[member_heading context..remote_ready_link]
893
894        template< typename List >
895        void remote_ready_link( List & lst) noexcept;
896
897[variablelist
898[[Effects:] [Stores `*this` in remote-ready-queue `lst`.]]
899[[Throws:] [Nothing]]
900[[Note:] [Argument `lst` must be a doubly-linked list from
901__boost_intrusive__.]]
902]
903
904[member_heading context..wait_link]
905
906        template< typename List >
907        void wait_link( List & lst) noexcept;
908
909[variablelist
910[[Effects:] [Stores `*this` in wait-queue `lst`.]]
911[[Throws:] [Nothing]]
912[[Note:] [Argument `lst` must be a doubly-linked list from
913__boost_intrusive__.]]
914]
915
916[member_heading context..ready_unlink]
917
918        void ready_unlink() noexcept;
919
920[variablelist
921[[Effects:] [Removes `*this` from ready-queue: undoes the effect of
922[member_link context..ready_link].]]
923[[Throws:] [Nothing]]
924]
925
926[member_heading context..remote_ready_unlink]
927
928        void remote_ready_unlink() noexcept;
929
930[variablelist
931[[Effects:] [Removes `*this` from remote-ready-queue.]]
932[[Throws:] [Nothing]]
933]
934
935[member_heading context..wait_unlink]
936
937        void wait_unlink() noexcept;
938
939[variablelist
940[[Effects:] [Removes `*this` from wait-queue.]]
941[[Throws:] [Nothing]]
942]
943
944[member_heading context..suspend]
945
946        void suspend() noexcept;
947
948[variablelist
949[[Effects:] [Suspends the running fiber (the fiber associated with `*this`)
950until some other fiber passes `this` to [member_link context..schedule].
951`*this` is marked as not-ready, and control passes to the scheduler to select
952another fiber to run.]]
953[[Throws:] [Nothing]]
954[[Note:] [This is a low-level API potentially useful for integration with
955other frameworks. It is not intended to be directly invoked by a typical
956application program.]]
957[[Note:] [The burden is on the caller to arrange for a call to `schedule()`
958with a pointer to `this` at some future time.]]
959]
960
961[member_heading context..schedule]
962
963        void schedule( context * ctx ) noexcept;
964
965[variablelist
966[[Effects:] [Mark the fiber associated with context `*ctx` as being ready to
967run. This does not immediately resume that fiber; rather it passes the fiber
968to the scheduler for subsequent resumption. If the scheduler is idle (has not
969returned from a call to [member_link algorithm..suspend_until]),
970[member_link algorithm..notify] is called to wake it up.]]
971[[Throws:] [Nothing]]
972[[Note:] [This is a low-level API potentially useful for integration with
973other frameworks. It is not intended to be directly invoked by a typical
974application program.]]
975[[Note:] [It is explicitly supported to call `schedule(ctx)` from a thread
976other than the one on which `*ctx` is currently suspended. The corresponding
977fiber will be resumed on its original thread in due course.]]
978[/[[Note:] [See [member_link context..migrate] for a way to migrate the
979suspended thread to the thread calling `schedule()`.]]]
980]
981
982[hding context_less..Non-member function [`operator<()]]
983
984        bool operator<( context const& l, context const& r) noexcept;
985
986[variablelist
987[[Returns:] [`true` if `l.get_id() < r.get_id()` is `true`, `false`
988otherwise.]]
989[[Throws:] [Nothing.]]
990]
991
992
993[endsect]
994