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