fiber/doc/fibers.xml
2018-10-22 10:13:30 +02:00

16750 lines
1.2 MiB

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE library PUBLIC "-//Boost//DTD BoostBook XML V1.0//EN" "http://www.boost.org/tools/boostbook/dtd/boostbook.dtd">
<library id="fiber" name="Fiber" dirname="fiber" last-revision="$Date: 2018/10/22 08:13:04 $"
xmlns:xi="http://www.w3.org/2001/XInclude">
<libraryinfo>
<authorgroup>
<author>
<firstname>Oliver</firstname> <surname>Kowalke</surname>
</author>
</authorgroup>
<copyright>
<year>2013</year> <holder>Oliver Kowalke</holder>
</copyright>
<legalnotice id="fiber.legal">
<para>
Distributed under the Boost Software License, Version 1.0. (See accompanying
file LICENSE_1_0.txt or copy at <ulink url="http://www.boost.org/LICENSE_1_0.txt">http://www.boost.org/LICENSE_1_0.txt</ulink>)
</para>
</legalnotice>
<librarypurpose>
C++ Library to cooperatively schedule and synchronize micro-threads
</librarypurpose>
<librarycategory name="category:text"></librarycategory>
</libraryinfo>
<title>Fiber</title>
<section id="fiber.overview">
<title><link linkend="fiber.overview">Overview</link></title>
<para>
<emphasis role="bold">Boost.Fiber</emphasis> provides a framework for micro-/userland-threads
(fibers) scheduled cooperatively. The API contains classes and functions to
manage and synchronize fibers similiarly to <ulink url="http://en.cppreference.com/w/cpp/thread">standard
thread support library</ulink>.
</para>
<para>
Each fiber has its own stack.
</para>
<para>
A fiber can save the current execution state, including all registers and CPU
flags, the instruction pointer, and the stack pointer and later restore this
state. The idea is to have multiple execution paths running on a single thread
using cooperative scheduling (versus threads, which are preemptively scheduled).
The running fiber decides explicitly when it should yield to allow another
fiber to run (context switching). <emphasis role="bold">Boost.Fiber</emphasis>
internally uses <ulink url="http://www.boost.org/doc/libs/release/libs/context/doc/html/context/cc.html"><emphasis>call/cc</emphasis></ulink>
from <ulink url="http://www.boost.org/doc/libs/release/libs/context/index.html">Boost.Context</ulink>;
the classes in this library manage, schedule and, when needed, synchronize
those execution contexts. A context switch between threads usually costs thousands
of CPU cycles on x86, compared to a fiber switch with less than a hundred cycles.
A fiber runs on a single thread at any point in time.
</para>
<para>
In order to use the classes and functions described here, you can either include
the specific headers specified by the descriptions of each class or function,
or include the master library header:
</para>
<programlisting><phrase role="preprocessor">#include</phrase> <phrase role="special">&lt;</phrase><phrase role="identifier">boost</phrase><phrase role="special">/</phrase><phrase role="identifier">fiber</phrase><phrase role="special">/</phrase><phrase role="identifier">all</phrase><phrase role="special">.</phrase><phrase role="identifier">hpp</phrase><phrase role="special">&gt;</phrase>
</programlisting>
<para>
which includes all the other headers in turn.
</para>
<para>
The namespaces used are:
</para>
<programlisting><phrase role="keyword">namespace</phrase> <phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">fibers</phrase>
<phrase role="keyword">namespace</phrase> <phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">this_fiber</phrase>
</programlisting>
<bridgehead renderas="sect3" id="fiber.overview.h0">
<phrase id="fiber.overview.fibers_and_threads"/><link linkend="fiber.overview.fibers_and_threads">Fibers
and Threads</link>
</bridgehead>
<para>
Control is cooperatively passed between fibers launched on a given thread.
At a given moment, on a given thread, at most one fiber is running.
</para>
<para>
Spawning additional fibers on a given thread does not distribute your program
across more hardware cores, though it can make more effective use of the core
on which it's running.
</para>
<para>
On the other hand, a fiber may safely access any resource exclusively owned
by its parent thread without explicitly needing to defend that resource against
concurrent access by other fibers on the same thread. You are already guaranteed
that no other fiber on that thread is concurrently touching that resource.
This can be particularly important when introducing concurrency in legacy code.
You can safely spawn fibers running old code, using asynchronous I/O to interleave
execution.
</para>
<para>
In effect, fibers provide a natural way to organize concurrent code based on
asynchronous I/O. Instead of chaining together completion handlers, code running
on a fiber can make what looks like a normal blocking function call. That call
can cheaply suspend the calling fiber, allowing other fibers on the same thread
to run. When the operation has completed, the suspended fiber resumes, without
having to explicitly save or restore its state. Its local stack variables persist
across the call.
</para>
<para>
A fiber can be migrated from one thread to another, though the library does
not do this by default. It is possible for you to supply a custom scheduler
that migrates fibers between threads. You may specify custom fiber properties
to help your scheduler decide which fibers are permitted to migrate. Please
see <link linkend="migration">Migrating fibers between threads</link> and
<link linkend="custom">Customization</link> for more details.
</para>
<para>
<emphasis role="bold">Boost.Fiber</emphasis> allows to <emphasis role="bold"><code><phrase
role="identifier">multiplex</phrase> <phrase role="identifier">fibers</phrase>
<phrase role="identifier">across</phrase> <phrase role="identifier">multiple</phrase>
<phrase role="identifier">cores</phrase></code></emphasis> (see <link linkend="class_numa_work_stealing"><code>numa::work_stealing</code></link>).
</para>
<para>
A fiber launched on a particular thread continues running on that thread unless
migrated. It might be unblocked (see <link linkend="blocking">Blocking</link>
below) by some other thread, but that only transitions the fiber from <quote>blocked</quote>
to <quote>ready</quote> on its current thread &mdash; it does not cause the fiber to
resume on the thread that unblocked it.
</para>
<anchor id="thread_local_storage"/>
<bridgehead renderas="sect3" id="fiber.overview.h1">
<phrase id="fiber.overview.thread_local_storage"/><link linkend="fiber.overview.thread_local_storage">thread-local
storage</link>
</bridgehead>
<para>
Unless migrated, a fiber may access thread-local storage; however that storage
will be shared among all fibers running on the same thread. For fiber-local
storage, please see <link linkend="class_fiber_specific_ptr"><code>fiber_specific_ptr</code></link>.
</para>
<anchor id="cross_thread_sync"/>
<bridgehead renderas="sect3" id="fiber.overview.h2">
<phrase id="fiber.overview.boost_fibers_no_atomics"/><link linkend="fiber.overview.boost_fibers_no_atomics">BOOST_FIBERS_NO_ATOMICS</link>
</bridgehead>
<para>
The fiber synchronization objects provided by this library will, by default,
safely synchronize fibers running on different threads. However, this level
of synchronization can be removed (for performance) by building the library
with <emphasis role="bold"><code><phrase role="identifier">BOOST_FIBERS_NO_ATOMICS</phrase></code></emphasis>
defined. When the library is built with that macro, you must ensure that all
the fibers referencing a particular synchronization object are running in the
same thread. Please see <link linkend="synchronization">Synchronization</link>.
</para>
<anchor id="blocking"/>
<bridgehead renderas="sect3" id="fiber.overview.h3">
<phrase id="fiber.overview.blocking"/><link linkend="fiber.overview.blocking">Blocking</link>
</bridgehead>
<para>
Normally, when this documentation states that a particular fiber <emphasis>blocks</emphasis>
(or equivalently, <emphasis>suspends),</emphasis> it means that it yields control,
allowing other fibers on the same thread to run. The synchronization mechanisms
provided by <emphasis role="bold">Boost.Fiber</emphasis> have this behavior.
</para>
<para>
A fiber may, of course, use normal thread synchronization mechanisms; however
a fiber that invokes any of these mechanisms will block its entire thread,
preventing any other fiber from running on that thread in the meantime. For
instance, when a fiber wants to wait for a value from another fiber in the
same thread, using <code><phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase
role="identifier">future</phrase></code> would be unfortunate: <code><phrase
role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">future</phrase><phrase
role="special">::</phrase><phrase role="identifier">get</phrase><phrase role="special">()</phrase></code>
would block the whole thread, preventing the other fiber from delivering its
value. Use <link linkend="class_future"><code>future&lt;&gt;</code></link> instead.
</para>
<para>
Similarly, a fiber that invokes a normal blocking I/O operation will block
its entire thread. Fiber authors are encouraged to consistently use asynchronous
I/O. <ulink url="http://www.boost.org/doc/libs/release/libs/asio/index.html">Boost.Asio</ulink>
and other asynchronous I/O operations can straightforwardly be adapted for
<emphasis role="bold">Boost.Fiber</emphasis>: see <link linkend="callbacks">Integrating
Fibers with Asynchronous Callbacks</link>.
</para>
<para>
<emphasis role="bold">Boost.Fiber</emphasis> depends upon <ulink url="http://www.boost.org/doc/libs/release/libs/context/index.html">Boost.Context</ulink>.
Boost version 1.61.0 or greater is required.
</para>
<note>
<para>
This library requires C++11!
</para>
</note>
<section id="fiber.overview.implementations__fcontext_t__ucontext_t_and_winfiber">
<title><anchor id="implementation"/><link linkend="fiber.overview.implementations__fcontext_t__ucontext_t_and_winfiber">Implementations:
fcontext_t, ucontext_t and WinFiber</link></title>
<para>
<emphasis role="bold">Boost.Fiber</emphasis> uses <ulink url="http://www.boost.org/doc/libs/release/libs/context/doc/html/context/cc.html"><emphasis>call/cc</emphasis></ulink>
from <ulink url="http://www.boost.org/doc/libs/release/libs/context/index.html">Boost.Context</ulink>
as building-block.
</para>
<bridgehead renderas="sect4" id="fiber.overview.implementations__fcontext_t__ucontext_t_and_winfiber.h0">
<phrase id="fiber.overview.implementations__fcontext_t__ucontext_t_and_winfiber.fcontext_t"/><link
linkend="fiber.overview.implementations__fcontext_t__ucontext_t_and_winfiber.fcontext_t">fcontext_t</link>
</bridgehead>
<para>
The implementation uses <code><phrase role="identifier">fcontext_t</phrase></code>
per default. fcontext_t is based on assembler and not available for all platforms.
It provides a much better performance than <code><phrase role="identifier">ucontext_t</phrase></code>
(the context switch takes two magnitudes of order less CPU cycles; see section
<ulink url="http://www.boost.org/doc/libs/release/libs/context/doc/html/context/performance.html"><emphasis>performance</emphasis></ulink>)
and <code><phrase role="identifier">WinFiber</phrase></code>.
</para>
<bridgehead renderas="sect4" id="fiber.overview.implementations__fcontext_t__ucontext_t_and_winfiber.h1">
<phrase id="fiber.overview.implementations__fcontext_t__ucontext_t_and_winfiber.ucontext_t"/><link
linkend="fiber.overview.implementations__fcontext_t__ucontext_t_and_winfiber.ucontext_t">ucontext_t</link>
</bridgehead>
<para>
As an alternative, <ulink url="https://en.wikipedia.org/wiki/Setcontext"><code><phrase
role="identifier">ucontext_t</phrase></code></ulink> can be used by compiling
with <code><phrase role="identifier">BOOST_USE_UCONTEXT</phrase></code> and
b2 property <code><phrase role="identifier">context</phrase><phrase role="special">-</phrase><phrase
role="identifier">impl</phrase><phrase role="special">=</phrase><phrase role="identifier">ucontext</phrase></code>.
<code><phrase role="identifier">ucontext_t</phrase></code> might be available
on a broader range of POSIX-platforms but has some <ulink url="http://www.boost.org/doc/libs/release/libs/context/doc/html/context/rational.html#ucontext"><emphasis>disadvantages</emphasis></ulink>
(for instance deprecated since POSIX.1-2003, not C99 conform).
</para>
<note>
<para>
<ulink url="http://www.boost.org/doc/libs/release/libs/context/doc/html/context/cc.html"><emphasis>call/cc</emphasis></ulink>
supports <link linkend="segmented"><emphasis>Segmented stacks</emphasis></link>
only with <code><phrase role="identifier">ucontext_t</phrase></code> as
its implementation.
</para>
</note>
<bridgehead renderas="sect4" id="fiber.overview.implementations__fcontext_t__ucontext_t_and_winfiber.h2">
<phrase id="fiber.overview.implementations__fcontext_t__ucontext_t_and_winfiber.winfiber"/><link
linkend="fiber.overview.implementations__fcontext_t__ucontext_t_and_winfiber.winfiber">WinFiber</link>
</bridgehead>
<para>
With <code><phrase role="identifier">BOOST_USE_WINFIB</phrase></code> and
b2 property <code><phrase role="identifier">context</phrase><phrase role="special">-</phrase><phrase
role="identifier">impl</phrase><phrase role="special">=</phrase><phrase role="identifier">winfib</phrase></code>
Win32-Fibers are used as implementation for <ulink url="http://www.boost.org/doc/libs/release/libs/context/doc/html/context/cc.html"><emphasis>call/cc</emphasis></ulink>.
</para>
<para>
Because the TIB (thread information block) is not fully described in the
MSDN, it might be possible that not all required TIB-parts are swapped.
</para>
<note>
<para>
The first call of <ulink url="http://www.boost.org/doc/libs/release/libs/context/doc/html/context/cc.html"><emphasis>call/cc</emphasis></ulink>
converts the thread into a Windows fiber by invoking <code><phrase role="identifier">ConvertThreadToFiber</phrase><phrase
role="special">()</phrase></code>. If desired, <code><phrase role="identifier">ConvertFiberToThread</phrase><phrase
role="special">()</phrase></code> has to be called by the user explicitly
in order to release resources allocated by <code><phrase role="identifier">ConvertThreadToFiber</phrase><phrase
role="special">()</phrase></code> (e.g. after using boost.context).
</para>
</note>
</section>
<important>
<para>
Windows using fcontext_t: turn off global program optimization (/GL) and
change /EHsc (compiler assumes that functions declared as extern &quot;C&quot;
never throw a C++ exception) to /EHs (tells compiler assumes that functions
declared as extern &quot;C&quot; may throw an exception).
</para>
</important>
</section>
<section id="fiber.fiber_mgmt">
<title><link linkend="fiber.fiber_mgmt">Fiber management</link></title>
<bridgehead renderas="sect3" id="fiber.fiber_mgmt.h0">
<phrase id="fiber.fiber_mgmt.synopsis"/><link linkend="fiber.fiber_mgmt.synopsis">Synopsis</link>
</bridgehead>
<programlisting><phrase role="preprocessor">#include</phrase> <phrase role="special">&lt;</phrase><phrase role="identifier">boost</phrase><phrase role="special">/</phrase><phrase role="identifier">fiber</phrase><phrase role="special">/</phrase><phrase role="identifier">all</phrase><phrase role="special">.</phrase><phrase role="identifier">hpp</phrase><phrase role="special">&gt;</phrase>
<phrase role="keyword">namespace</phrase> <phrase role="identifier">boost</phrase> <phrase role="special">{</phrase>
<phrase role="keyword">namespace</phrase> <phrase role="identifier">fibers</phrase> <phrase role="special">{</phrase>
<phrase role="keyword">class</phrase> <phrase role="identifier">fiber</phrase><phrase role="special">;</phrase>
<phrase role="keyword">bool</phrase> <phrase role="keyword">operator</phrase><phrase role="special">&lt;(</phrase> <phrase role="identifier">fiber</phrase> <phrase role="keyword">const</phrase><phrase role="special">&amp;</phrase> <phrase role="identifier">l</phrase><phrase role="special">,</phrase> <phrase role="identifier">fiber</phrase> <phrase role="keyword">const</phrase><phrase role="special">&amp;</phrase> <phrase role="identifier">r</phrase><phrase role="special">)</phrase> <phrase role="keyword">noexcept</phrase><phrase role="special">;</phrase>
<phrase role="keyword">void</phrase> <phrase role="identifier">swap</phrase><phrase role="special">(</phrase> <phrase role="identifier">fiber</phrase> <phrase role="special">&amp;</phrase> <phrase role="identifier">l</phrase><phrase role="special">,</phrase> <phrase role="identifier">fiber</phrase> <phrase role="special">&amp;</phrase> <phrase role="identifier">r</phrase><phrase role="special">)</phrase> <phrase role="keyword">noexcept</phrase><phrase role="special">;</phrase>
<phrase role="keyword">template</phrase><phrase role="special">&lt;</phrase> <phrase role="keyword">typename</phrase> <phrase role="identifier">SchedAlgo</phrase><phrase role="special">,</phrase> <phrase role="keyword">typename</phrase> <phrase role="special">...</phrase> <phrase role="identifier">Args</phrase> <phrase role="special">&gt;</phrase>
<phrase role="keyword">void</phrase> <phrase role="identifier">use_scheduling_algorithm</phrase><phrase role="special">(</phrase> <phrase role="identifier">Args</phrase> <phrase role="special">&amp;&amp;</phrase> <phrase role="special">...</phrase> <phrase role="identifier">args</phrase><phrase role="special">);</phrase>
<phrase role="keyword">bool</phrase> <phrase role="identifier">has_ready_fibers</phrase><phrase role="special">();</phrase>
<phrase role="keyword">namespace</phrase> <phrase role="identifier">algo</phrase> <phrase role="special">{</phrase>
<phrase role="keyword">struct</phrase> <phrase role="identifier">algorithm</phrase><phrase role="special">;</phrase>
<phrase role="keyword">template</phrase><phrase role="special">&lt;</phrase> <phrase role="keyword">typename</phrase> <phrase role="identifier">PROPS</phrase> <phrase role="special">&gt;</phrase>
<phrase role="keyword">struct</phrase> <phrase role="identifier">algorithm_with_properties</phrase><phrase role="special">;</phrase>
<phrase role="keyword">class</phrase> <phrase role="identifier">round_robin</phrase><phrase role="special">;</phrase>
<phrase role="keyword">class</phrase> <phrase role="identifier">shared_round_robin</phrase><phrase role="special">;</phrase>
<phrase role="special">}}</phrase>
<phrase role="keyword">namespace</phrase> <phrase role="identifier">this_fiber</phrase> <phrase role="special">{</phrase>
<phrase role="identifier">fibers</phrase><phrase role="special">::</phrase><phrase role="identifier">id</phrase> <phrase role="identifier">get_id</phrase><phrase role="special">()</phrase> <phrase role="keyword">noexcept</phrase><phrase role="special">;</phrase>
<phrase role="keyword">void</phrase> <phrase role="identifier">yield</phrase><phrase role="special">();</phrase>
<phrase role="keyword">template</phrase><phrase role="special">&lt;</phrase> <phrase role="keyword">typename</phrase> <phrase role="identifier">Clock</phrase><phrase role="special">,</phrase> <phrase role="keyword">typename</phrase> <phrase role="identifier">Duration</phrase> <phrase role="special">&gt;</phrase>
<phrase role="keyword">void</phrase> <phrase role="identifier">sleep_until</phrase><phrase role="special">(</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">chrono</phrase><phrase role="special">::</phrase><phrase role="identifier">time_point</phrase><phrase role="special">&lt;</phrase> <phrase role="identifier">Clock</phrase><phrase role="special">,</phrase> <phrase role="identifier">Duration</phrase> <phrase role="special">&gt;</phrase> <phrase role="keyword">const</phrase><phrase role="special">&amp;</phrase> <phrase role="identifier">abs_time</phrase><phrase role="special">)</phrase>
<phrase role="keyword">template</phrase><phrase role="special">&lt;</phrase> <phrase role="keyword">typename</phrase> <phrase role="identifier">Rep</phrase><phrase role="special">,</phrase> <phrase role="keyword">typename</phrase> <phrase role="identifier">Period</phrase> <phrase role="special">&gt;</phrase>
<phrase role="keyword">void</phrase> <phrase role="identifier">sleep_for</phrase><phrase role="special">(</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">chrono</phrase><phrase role="special">::</phrase><phrase role="identifier">duration</phrase><phrase role="special">&lt;</phrase> <phrase role="identifier">Rep</phrase><phrase role="special">,</phrase> <phrase role="identifier">Period</phrase> <phrase role="special">&gt;</phrase> <phrase role="keyword">const</phrase><phrase role="special">&amp;</phrase> <phrase role="identifier">rel_time</phrase><phrase role="special">);</phrase>
<phrase role="keyword">template</phrase><phrase role="special">&lt;</phrase> <phrase role="keyword">typename</phrase> <phrase role="identifier">PROPS</phrase> <phrase role="special">&gt;</phrase>
<phrase role="identifier">PROPS</phrase> <phrase role="special">&amp;</phrase> <phrase role="identifier">properties</phrase><phrase role="special">();</phrase>
<phrase role="special">}</phrase>
</programlisting>
<bridgehead renderas="sect3" id="fiber.fiber_mgmt.h1">
<phrase id="fiber.fiber_mgmt.tutorial"/><link linkend="fiber.fiber_mgmt.tutorial">Tutorial</link>
</bridgehead>
<para>
Each <link linkend="class_fiber"><code>fiber</code></link> represents a micro-thread which will be launched and managed
cooperatively by a scheduler. Objects of type <link linkend="class_fiber"><code>fiber</code></link> are move-only.
</para>
<programlisting><phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">fibers</phrase><phrase role="special">::</phrase><phrase role="identifier">fiber</phrase> <phrase role="identifier">f1</phrase><phrase role="special">;</phrase> <phrase role="comment">// not-a-fiber</phrase>
<phrase role="keyword">void</phrase> <phrase role="identifier">f</phrase><phrase role="special">()</phrase> <phrase role="special">{</phrase>
<phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">fibers</phrase><phrase role="special">::</phrase><phrase role="identifier">fiber</phrase> <phrase role="identifier">f2</phrase><phrase role="special">(</phrase> <phrase role="identifier">some_fn</phrase><phrase role="special">);</phrase>
<phrase role="identifier">f1</phrase> <phrase role="special">=</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">move</phrase><phrase role="special">(</phrase> <phrase role="identifier">f2</phrase><phrase role="special">);</phrase> <phrase role="comment">// f2 moved to f1</phrase>
<phrase role="special">}</phrase>
</programlisting>
<bridgehead renderas="sect3" id="fiber.fiber_mgmt.h2">
<phrase id="fiber.fiber_mgmt.launching"/><link linkend="fiber.fiber_mgmt.launching">Launching</link>
</bridgehead>
<para>
A new fiber is launched by passing an object of a callable type that can be
invoked with no parameters. If the object must not be copied or moved, then
<emphasis>std::ref</emphasis> can be used to pass in a reference to the function
object. In this case, the user must ensure that the referenced object outlives
the newly-created fiber.
</para>
<programlisting><phrase role="keyword">struct</phrase> <phrase role="identifier">callable</phrase> <phrase role="special">{</phrase>
<phrase role="keyword">void</phrase> <phrase role="keyword">operator</phrase><phrase role="special">()();</phrase>
<phrase role="special">};</phrase>
<phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">fibers</phrase><phrase role="special">::</phrase><phrase role="identifier">fiber</phrase> <phrase role="identifier">copies_are_safe</phrase><phrase role="special">()</phrase> <phrase role="special">{</phrase>
<phrase role="identifier">callable</phrase> <phrase role="identifier">x</phrase><phrase role="special">;</phrase>
<phrase role="keyword">return</phrase> <phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">fibers</phrase><phrase role="special">::</phrase><phrase role="identifier">fiber</phrase><phrase role="special">(</phrase> <phrase role="identifier">x</phrase><phrase role="special">);</phrase>
<phrase role="special">}</phrase> <phrase role="comment">// x is destroyed, but the newly-created fiber has a copy, so this is OK</phrase>
<phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">fibers</phrase><phrase role="special">::</phrase><phrase role="identifier">fiber</phrase> <phrase role="identifier">oops</phrase><phrase role="special">()</phrase> <phrase role="special">{</phrase>
<phrase role="identifier">callable</phrase> <phrase role="identifier">x</phrase><phrase role="special">;</phrase>
<phrase role="keyword">return</phrase> <phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">fibers</phrase><phrase role="special">::</phrase><phrase role="identifier">fiber</phrase><phrase role="special">(</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">ref</phrase><phrase role="special">(</phrase> <phrase role="identifier">x</phrase><phrase role="special">)</phrase> <phrase role="special">);</phrase>
<phrase role="special">}</phrase> <phrase role="comment">// x is destroyed, but the newly-created fiber still has a reference</phrase>
<phrase role="comment">// this leads to undefined behaviour</phrase>
</programlisting>
<para>
The spawned <link linkend="class_fiber"><code>fiber</code></link> does not immediately start running. It is enqueued
in the list of ready-to-run fibers, and will run when the scheduler gets around
to it.
</para>
<anchor id="exceptions"/>
<bridgehead renderas="sect3" id="fiber.fiber_mgmt.h3">
<phrase id="fiber.fiber_mgmt.exceptions"/><link linkend="fiber.fiber_mgmt.exceptions">Exceptions</link>
</bridgehead>
<para>
An exception escaping from the function or callable object passed to the <link linkend="class_fiber"><code>fiber</code></link>
constructor
calls <code><phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase
role="identifier">terminate</phrase><phrase role="special">()</phrase></code>.
If you need to know which exception was thrown, use <link linkend="class_future"><code>future&lt;&gt;</code></link> or
<link linkend="class_packaged_task"><code>packaged_task&lt;&gt;</code></link>.
</para>
<bridgehead renderas="sect3" id="fiber.fiber_mgmt.h4">
<phrase id="fiber.fiber_mgmt.detaching"/><link linkend="fiber.fiber_mgmt.detaching">Detaching</link>
</bridgehead>
<para>
A <link linkend="class_fiber"><code>fiber</code></link> can be detached by explicitly invoking the <link linkend="fiber_detach"><code>fiber::detach()</code></link> member
function. After <link linkend="fiber_detach"><code>fiber::detach()</code></link> is called on a fiber object, that
object represents <emphasis>not-a-fiber</emphasis>. The fiber object may then
safely be destroyed.
</para>
<programlisting><phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">fibers</phrase><phrase role="special">::</phrase><phrase role="identifier">fiber</phrase><phrase role="special">(</phrase> <phrase role="identifier">some_fn</phrase><phrase role="special">).</phrase><phrase role="identifier">detach</phrase><phrase role="special">();</phrase>
</programlisting>
<para>
<emphasis role="bold">Boost.Fiber</emphasis> provides a number of ways to wait
for a running fiber to complete. You can coordinate even with a detached fiber
using a <link linkend="class_mutex"><code>mutex</code></link>, or <link linkend="class_condition_variable"><code>condition_variable</code></link>, or
any of the other <link linkend="synchronization">synchronization objects</link>
provided by the library.
</para>
<para>
If a detached fiber is still running when the thread&#8217;s main fiber terminates,
the thread will not shut down.
</para>
<bridgehead renderas="sect3" id="fiber.fiber_mgmt.h5">
<phrase id="fiber.fiber_mgmt.joining"/><link linkend="fiber.fiber_mgmt.joining">Joining</link>
</bridgehead>
<para>
In order to wait for a fiber to finish, the <link linkend="fiber_join"><code>fiber::join()</code></link> member function
of the <link linkend="class_fiber"><code>fiber</code></link> object can be used. <link linkend="fiber_join"><code>fiber::join()</code></link> will block
until the <link linkend="class_fiber"><code>fiber</code></link> object has completed.
</para>
<programlisting><phrase role="keyword">void</phrase> <phrase role="identifier">some_fn</phrase><phrase role="special">()</phrase> <phrase role="special">{</phrase>
<phrase role="special">...</phrase>
<phrase role="special">}</phrase>
<phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">fibers</phrase><phrase role="special">::</phrase><phrase role="identifier">fiber</phrase> <phrase role="identifier">f</phrase><phrase role="special">(</phrase> <phrase role="identifier">some_fn</phrase><phrase role="special">);</phrase>
<phrase role="special">...</phrase>
<phrase role="identifier">f</phrase><phrase role="special">.</phrase><phrase role="identifier">join</phrase><phrase role="special">();</phrase>
</programlisting>
<para>
If the fiber has already completed, then <link linkend="fiber_join"><code>fiber::join()</code></link> returns immediately
and the joined <link linkend="class_fiber"><code>fiber</code></link> object becomes <emphasis>not-a-fiber</emphasis>.
</para>
<bridgehead renderas="sect3" id="fiber.fiber_mgmt.h6">
<phrase id="fiber.fiber_mgmt.destruction"/><link linkend="fiber.fiber_mgmt.destruction">Destruction</link>
</bridgehead>
<para>
When a <link linkend="class_fiber"><code>fiber</code></link> object representing a valid execution context (the fiber
is <link linkend="fiber_joinable"><code>fiber::joinable()</code></link>) is destroyed, the program terminates. If
you intend the fiber to outlive the <link linkend="class_fiber"><code>fiber</code></link> object that launched it,
use the <link linkend="fiber_detach"><code>fiber::detach()</code></link> method.
</para>
<programlisting><phrase role="special">{</phrase>
<phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">fibers</phrase><phrase role="special">::</phrase><phrase role="identifier">fiber</phrase> <phrase role="identifier">f</phrase><phrase role="special">(</phrase> <phrase role="identifier">some_fn</phrase><phrase role="special">);</phrase>
<phrase role="special">}</phrase> <phrase role="comment">// std::terminate() will be called</phrase>
<phrase role="special">{</phrase>
<phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">fibers</phrase><phrase role="special">::</phrase><phrase role="identifier">fiber</phrase> <phrase role="identifier">f</phrase><phrase role="special">(</phrase><phrase role="identifier">some_fn</phrase><phrase role="special">);</phrase>
<phrase role="identifier">f</phrase><phrase role="special">.</phrase><phrase role="identifier">detach</phrase><phrase role="special">();</phrase>
<phrase role="special">}</phrase> <phrase role="comment">// okay, program continues</phrase>
</programlisting>
<anchor id="class_fiber_id"/>
<bridgehead renderas="sect3" id="fiber.fiber_mgmt.h7">
<phrase id="fiber.fiber_mgmt.fiber_ids"/><link linkend="fiber.fiber_mgmt.fiber_ids">Fiber
IDs</link>
</bridgehead>
<para>
Objects of class <link linkend="class_fiber_id"><code><phrase role="identifier">fiber</phrase><phrase
role="special">::</phrase><phrase role="identifier">id</phrase></code></link> can be
used to identify fibers. Each running <link linkend="class_fiber"><code>fiber</code></link> has a unique <link linkend="class_fiber_id"><code><phrase
role="identifier">fiber</phrase><phrase role="special">::</phrase><phrase role="identifier">id</phrase></code></link> obtainable
from the corresponding <link linkend="class_fiber"><code>fiber</code></link>
by calling the <link linkend="fiber_get_id"><code>fiber::get_id()</code></link> member
function. Objects of class <link linkend="class_fiber_id"><code><phrase role="identifier">fiber</phrase><phrase
role="special">::</phrase><phrase role="identifier">id</phrase></code></link> can be
copied, and used as keys in associative containers: the full range of comparison
operators is provided. They can also be written to an output stream using the
stream insertion operator, though the output format is unspecified.
</para>
<para>
Each instance of <link linkend="class_fiber_id"><code><phrase role="identifier">fiber</phrase><phrase
role="special">::</phrase><phrase role="identifier">id</phrase></code></link> either
refers to some fiber, or <emphasis>not-a-fiber</emphasis>. Instances that refer
to <emphasis>not-a-fiber</emphasis> compare equal to each other, but not equal
to any instances that refer to an actual fiber. The comparison operators on
<link linkend="class_fiber_id"><code><phrase role="identifier">fiber</phrase><phrase role="special">::</phrase><phrase
role="identifier">id</phrase></code></link> yield a total order for every non-equal
<link linkend="class_fiber_id"><code><phrase role="identifier">fiber</phrase><phrase role="special">::</phrase><phrase
role="identifier">id</phrase></code></link>.
</para>
<anchor id="class_launch"/>
<bridgehead renderas="sect3" id="fiber.fiber_mgmt.h8">
<phrase id="fiber.fiber_mgmt.enumeration__code__phrase_role__identifier__launch__phrase___code_"/><link
linkend="fiber.fiber_mgmt.enumeration__code__phrase_role__identifier__launch__phrase___code_">Enumeration
<code><phrase role="identifier">launch</phrase></code></link>
</bridgehead>
<para>
<code><phrase role="identifier">launch</phrase></code> specifies whether control
passes immediately into a newly-launched fiber.
</para>
<programlisting><phrase role="keyword">enum</phrase> <phrase role="keyword">class</phrase> <phrase role="identifier">launch</phrase> <phrase role="special">{</phrase>
<phrase role="identifier">dispatch</phrase><phrase role="special">,</phrase>
<phrase role="identifier">post</phrase>
<phrase role="special">};</phrase>
</programlisting>
<bridgehead renderas="sect3" id="fiber.fiber_mgmt.h9">
<phrase id="fiber.fiber_mgmt._code__phrase_role__identifier__dispatch__phrase___code_"/><link
linkend="fiber.fiber_mgmt._code__phrase_role__identifier__dispatch__phrase___code_"><code><phrase
role="identifier">dispatch</phrase></code></link>
</bridgehead>
<variablelist>
<title></title>
<varlistentry>
<term>Effects:</term>
<listitem>
<para>
A fiber launched with <code><phrase role="identifier">launch</phrase>
<phrase role="special">==</phrase> <phrase role="identifier">dispatch</phrase></code>
is entered immediately. In other words, launching a fiber with <code><phrase
role="identifier">dispatch</phrase></code> suspends the caller (the previously-running
fiber) until the fiber scheduler has a chance to resume it later.
</para>
</listitem>
</varlistentry>
</variablelist>
<bridgehead renderas="sect3" id="fiber.fiber_mgmt.h10">
<phrase id="fiber.fiber_mgmt._code__phrase_role__identifier__post__phrase___code_"/><link
linkend="fiber.fiber_mgmt._code__phrase_role__identifier__post__phrase___code_"><code><phrase
role="identifier">post</phrase></code></link>
</bridgehead>
<variablelist>
<title></title>
<varlistentry>
<term>Effects:</term>
<listitem>
<para>
A fiber launched with <code><phrase role="identifier">launch</phrase>
<phrase role="special">==</phrase> <phrase role="identifier">post</phrase></code>
is passed to the fiber scheduler as ready, but it is not yet entered.
The caller (the previously-running fiber) continues executing. The newly-launched
fiber will be entered when the fiber scheduler has a chance to resume
it later.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>Note:</term>
<listitem>
<para>
If <code><phrase role="identifier">launch</phrase></code> is not explicitly
specified, <code><phrase role="identifier">post</phrase></code> is the
default.
</para>
</listitem>
</varlistentry>
</variablelist>
<section id="fiber.fiber_mgmt.fiber">
<title><anchor id="class_fiber"/><link linkend="fiber.fiber_mgmt.fiber">Class
<code><phrase role="identifier">fiber</phrase></code></link></title>
<programlisting><phrase role="preprocessor">#include</phrase> <phrase role="special">&lt;</phrase><phrase role="identifier">boost</phrase><phrase role="special">/</phrase><phrase role="identifier">fiber</phrase><phrase role="special">/</phrase><phrase role="identifier">fiber</phrase><phrase role="special">.</phrase><phrase role="identifier">hpp</phrase><phrase role="special">&gt;</phrase>
<phrase role="keyword">namespace</phrase> <phrase role="identifier">boost</phrase> <phrase role="special">{</phrase>
<phrase role="keyword">namespace</phrase> <phrase role="identifier">fibers</phrase> <phrase role="special">{</phrase>
<phrase role="keyword">class</phrase> <phrase role="identifier">fiber</phrase> <phrase role="special">{</phrase>
<phrase role="keyword">public</phrase><phrase role="special">:</phrase>
<phrase role="keyword">class</phrase> <phrase role="identifier">id</phrase><phrase role="special">;</phrase>
<phrase role="keyword">constexpr</phrase> <phrase role="identifier">fiber</phrase><phrase role="special">()</phrase> <phrase role="keyword">noexcept</phrase><phrase role="special">;</phrase>
<phrase role="keyword">template</phrase><phrase role="special">&lt;</phrase> <phrase role="keyword">typename</phrase> <phrase role="identifier">Fn</phrase><phrase role="special">,</phrase> <phrase role="keyword">typename</phrase> <phrase role="special">...</phrase> <phrase role="identifier">Args</phrase> <phrase role="special">&gt;</phrase>
<phrase role="identifier">fiber</phrase><phrase role="special">(</phrase> <phrase role="identifier">Fn</phrase> <phrase role="special">&amp;&amp;,</phrase> <phrase role="identifier">Args</phrase> <phrase role="special">&amp;&amp;</phrase> <phrase role="special">...);</phrase>
<phrase role="keyword">template</phrase><phrase role="special">&lt;</phrase> <phrase role="keyword">typename</phrase> <phrase role="identifier">Fn</phrase><phrase role="special">,</phrase> <phrase role="keyword">typename</phrase> <phrase role="special">...</phrase> <phrase role="identifier">Args</phrase> <phrase role="special">&gt;</phrase>
<phrase role="identifier">fiber</phrase><phrase role="special">(</phrase> <link linkend="class_launch"><code><phrase role="identifier">launch</phrase></code></link><phrase role="special">,</phrase> <phrase role="identifier">Fn</phrase> <phrase role="special">&amp;&amp;,</phrase> <phrase role="identifier">Args</phrase> <phrase role="special">&amp;&amp;</phrase> <phrase role="special">...);</phrase>
<phrase role="keyword">template</phrase><phrase role="special">&lt;</phrase> <phrase role="keyword">typename</phrase> <link linkend="stack_allocator_concept"><code><phrase role="identifier">StackAllocator</phrase></code></link><phrase role="special">,</phrase> <phrase role="keyword">typename</phrase> <phrase role="identifier">Fn</phrase><phrase role="special">,</phrase> <phrase role="keyword">typename</phrase> <phrase role="special">...</phrase> <phrase role="identifier">Args</phrase> <phrase role="special">&gt;</phrase>
<phrase role="identifier">fiber</phrase><phrase role="special">(</phrase> <ulink url="http://en.cppreference.com/w/cpp/memory/allocator_arg_t"><code><phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">allocator_arg_t</phrase></code></ulink><phrase role="special">,</phrase> <phrase role="identifier">StackAllocator</phrase> <phrase role="special">&amp;&amp;,</phrase> <phrase role="identifier">Fn</phrase> <phrase role="special">&amp;&amp;,</phrase> <phrase role="identifier">Args</phrase> <phrase role="special">&amp;&amp;</phrase> <phrase role="special">...);</phrase>
<phrase role="keyword">template</phrase><phrase role="special">&lt;</phrase> <phrase role="keyword">typename</phrase> <link linkend="stack_allocator_concept"><code><phrase role="identifier">StackAllocator</phrase></code></link><phrase role="special">,</phrase> <phrase role="keyword">typename</phrase> <phrase role="identifier">Fn</phrase><phrase role="special">,</phrase> <phrase role="keyword">typename</phrase> <phrase role="special">...</phrase> <phrase role="identifier">Args</phrase> <phrase role="special">&gt;</phrase>
<phrase role="identifier">fiber</phrase><phrase role="special">(</phrase> <link linkend="class_launch"><code><phrase role="identifier">launch</phrase></code></link><phrase role="special">,</phrase> <ulink url="http://en.cppreference.com/w/cpp/memory/allocator_arg_t"><code><phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">allocator_arg_t</phrase></code></ulink><phrase role="special">,</phrase> <phrase role="identifier">StackAllocator</phrase> <phrase role="special">&amp;&amp;,</phrase> <phrase role="identifier">Fn</phrase> <phrase role="special">&amp;&amp;,</phrase> <phrase role="identifier">Args</phrase> <phrase role="special">&amp;&amp;</phrase> <phrase role="special">...);</phrase>
<phrase role="special">~</phrase><phrase role="identifier">fiber</phrase><phrase role="special">();</phrase>
<phrase role="identifier">fiber</phrase><phrase role="special">(</phrase> <phrase role="identifier">fiber</phrase> <phrase role="keyword">const</phrase><phrase role="special">&amp;)</phrase> <phrase role="special">=</phrase> <phrase role="keyword">delete</phrase><phrase role="special">;</phrase>
<phrase role="identifier">fiber</phrase> <phrase role="special">&amp;</phrase> <phrase role="keyword">operator</phrase><phrase role="special">=(</phrase> <phrase role="identifier">fiber</phrase> <phrase role="keyword">const</phrase><phrase role="special">&amp;)</phrase> <phrase role="special">=</phrase> <phrase role="keyword">delete</phrase><phrase role="special">;</phrase>
<phrase role="identifier">fiber</phrase><phrase role="special">(</phrase> <phrase role="identifier">fiber</phrase> <phrase role="special">&amp;&amp;)</phrase> <phrase role="keyword">noexcept</phrase><phrase role="special">;</phrase>
<phrase role="identifier">fiber</phrase> <phrase role="special">&amp;</phrase> <phrase role="keyword">operator</phrase><phrase role="special">=(</phrase> <phrase role="identifier">fiber</phrase> <phrase role="special">&amp;&amp;)</phrase> <phrase role="keyword">noexcept</phrase><phrase role="special">;</phrase>
<phrase role="keyword">void</phrase> <phrase role="identifier">swap</phrase><phrase role="special">(</phrase> <phrase role="identifier">fiber</phrase> <phrase role="special">&amp;)</phrase> <phrase role="keyword">noexcept</phrase><phrase role="special">;</phrase>
<phrase role="keyword">bool</phrase> <phrase role="identifier">joinable</phrase><phrase role="special">()</phrase> <phrase role="keyword">const</phrase> <phrase role="keyword">noexcept</phrase><phrase role="special">;</phrase>
<phrase role="identifier">id</phrase> <phrase role="identifier">get_id</phrase><phrase role="special">()</phrase> <phrase role="keyword">const</phrase> <phrase role="keyword">noexcept</phrase><phrase role="special">;</phrase>
<phrase role="keyword">void</phrase> <phrase role="identifier">detach</phrase><phrase role="special">();</phrase>
<phrase role="keyword">void</phrase> <phrase role="identifier">join</phrase><phrase role="special">();</phrase>
<phrase role="keyword">template</phrase><phrase role="special">&lt;</phrase> <phrase role="keyword">typename</phrase> <phrase role="identifier">PROPS</phrase> <phrase role="special">&gt;</phrase>
<phrase role="identifier">PROPS</phrase> <phrase role="special">&amp;</phrase> <phrase role="identifier">properties</phrase><phrase role="special">();</phrase>
<phrase role="special">};</phrase>
<phrase role="keyword">bool</phrase> <phrase role="keyword">operator</phrase><phrase role="special">&lt;(</phrase> <phrase role="identifier">fiber</phrase> <phrase role="keyword">const</phrase><phrase role="special">&amp;,</phrase> <phrase role="identifier">fiber</phrase> <phrase role="keyword">const</phrase><phrase role="special">&amp;)</phrase> <phrase role="keyword">noexcept</phrase><phrase role="special">;</phrase>
<phrase role="keyword">void</phrase> <phrase role="identifier">swap</phrase><phrase role="special">(</phrase> <phrase role="identifier">fiber</phrase> <phrase role="special">&amp;,</phrase> <phrase role="identifier">fiber</phrase> <phrase role="special">&amp;)</phrase> <phrase role="keyword">noexcept</phrase><phrase role="special">;</phrase>
<phrase role="keyword">template</phrase><phrase role="special">&lt;</phrase> <phrase role="keyword">typename</phrase> <phrase role="identifier">SchedAlgo</phrase><phrase role="special">,</phrase> <phrase role="keyword">typename</phrase> <phrase role="special">...</phrase> <phrase role="identifier">Args</phrase> <phrase role="special">&gt;</phrase>
<phrase role="keyword">void</phrase> <phrase role="identifier">use_scheduling_algorithm</phrase><phrase role="special">(</phrase> <phrase role="identifier">Args</phrase> <phrase role="special">&amp;&amp;</phrase> <phrase role="special">...)</phrase> <phrase role="keyword">noexcept</phrase><phrase role="special">;</phrase>
<phrase role="keyword">bool</phrase> <phrase role="identifier">has_ready_fibers</phrase><phrase role="special">()</phrase> <phrase role="keyword">noexcept</phrase><phrase role="special">;</phrase>
<phrase role="special">}}</phrase>
</programlisting>
<bridgehead renderas="sect4" id="fiber.fiber_mgmt.fiber.h0">
<phrase id="fiber.fiber_mgmt.fiber.default_constructor"/><link linkend="fiber.fiber_mgmt.fiber.default_constructor">Default
constructor</link>
</bridgehead>
<programlisting><phrase role="keyword">constexpr</phrase> <phrase role="identifier">fiber</phrase><phrase role="special">()</phrase> <phrase role="keyword">noexcept</phrase><phrase role="special">;</phrase>
</programlisting>
<variablelist>
<title></title>
<varlistentry>
<term>Effects:</term>
<listitem>
<para>
Constructs a <link linkend="class_fiber"><code>fiber</code></link> instance that refers to <emphasis>not-a-fiber</emphasis>.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>Postconditions:</term>
<listitem>
<para>
<code><phrase role="keyword">this</phrase><phrase role="special">-&gt;</phrase><phrase
role="identifier">get_id</phrase><phrase role="special">()</phrase>
<phrase role="special">==</phrase> <phrase role="identifier">fiber</phrase><phrase
role="special">::</phrase><phrase role="identifier">id</phrase><phrase
role="special">()</phrase></code>
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>Throws:</term>
<listitem>
<para>
Nothing
</para>
</listitem>
</varlistentry>
</variablelist>
<anchor id="fiber_fiber"/>
<bridgehead renderas="sect4" id="fiber.fiber_mgmt.fiber.h1">
<phrase id="fiber.fiber_mgmt.fiber.constructor"/><link linkend="fiber.fiber_mgmt.fiber.constructor">Constructor</link>
</bridgehead>
<programlisting><phrase role="keyword">template</phrase><phrase role="special">&lt;</phrase> <phrase role="keyword">typename</phrase> <phrase role="identifier">Fn</phrase><phrase role="special">,</phrase> <phrase role="keyword">typename</phrase> <phrase role="special">...</phrase> <phrase role="identifier">Args</phrase> <phrase role="special">&gt;</phrase>
<phrase role="identifier">fiber</phrase><phrase role="special">(</phrase> <phrase role="identifier">Fn</phrase> <phrase role="special">&amp;&amp;</phrase> <phrase role="identifier">fn</phrase><phrase role="special">,</phrase> <phrase role="identifier">Args</phrase> <phrase role="special">&amp;&amp;</phrase> <phrase role="special">...</phrase> <phrase role="identifier">args</phrase><phrase role="special">);</phrase>
<phrase role="keyword">template</phrase><phrase role="special">&lt;</phrase> <phrase role="keyword">typename</phrase> <phrase role="identifier">Fn</phrase><phrase role="special">,</phrase> <phrase role="keyword">typename</phrase> <phrase role="special">...</phrase> <phrase role="identifier">Args</phrase> <phrase role="special">&gt;</phrase>
<phrase role="identifier">fiber</phrase><phrase role="special">(</phrase> <link linkend="class_launch"><code><phrase role="identifier">launch</phrase></code></link> <phrase role="identifier">policy</phrase><phrase role="special">,</phrase> <phrase role="identifier">Fn</phrase> <phrase role="special">&amp;&amp;</phrase> <phrase role="identifier">fn</phrase><phrase role="special">,</phrase> <phrase role="identifier">Args</phrase> <phrase role="special">&amp;&amp;</phrase> <phrase role="special">...</phrase> <phrase role="identifier">args</phrase><phrase role="special">);</phrase>
<phrase role="keyword">template</phrase><phrase role="special">&lt;</phrase> <phrase role="keyword">typename</phrase> <link linkend="stack_allocator_concept"><code><phrase role="identifier">StackAllocator</phrase></code></link><phrase role="special">,</phrase> <phrase role="keyword">typename</phrase> <phrase role="identifier">Fn</phrase><phrase role="special">,</phrase> <phrase role="keyword">typename</phrase> <phrase role="special">...</phrase> <phrase role="identifier">Args</phrase> <phrase role="special">&gt;</phrase>
<phrase role="identifier">fiber</phrase><phrase role="special">(</phrase> <ulink url="http://en.cppreference.com/w/cpp/memory/allocator_arg_t"><code><phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">allocator_arg_t</phrase></code></ulink><phrase role="special">,</phrase> <phrase role="identifier">StackAllocator</phrase> <phrase role="special">&amp;&amp;</phrase> <phrase role="identifier">salloc</phrase><phrase role="special">,</phrase> <phrase role="identifier">Fn</phrase> <phrase role="special">&amp;&amp;</phrase> <phrase role="identifier">fn</phrase><phrase role="special">,</phrase> <phrase role="identifier">Args</phrase> <phrase role="special">&amp;&amp;</phrase> <phrase role="special">...</phrase> <phrase role="identifier">args</phrase><phrase role="special">);</phrase>
<phrase role="keyword">template</phrase><phrase role="special">&lt;</phrase> <phrase role="keyword">typename</phrase> <link linkend="stack_allocator_concept"><code><phrase role="identifier">StackAllocator</phrase></code></link><phrase role="special">,</phrase> <phrase role="keyword">typename</phrase> <phrase role="identifier">Fn</phrase><phrase role="special">,</phrase> <phrase role="keyword">typename</phrase> <phrase role="special">...</phrase> <phrase role="identifier">Args</phrase> <phrase role="special">&gt;</phrase>
<phrase role="identifier">fiber</phrase><phrase role="special">(</phrase> <link linkend="class_launch"><code><phrase role="identifier">launch</phrase></code></link> <phrase role="identifier">policy</phrase><phrase role="special">,</phrase> <ulink url="http://en.cppreference.com/w/cpp/memory/allocator_arg_t"><code><phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">allocator_arg_t</phrase></code></ulink><phrase role="special">,</phrase> <phrase role="identifier">StackAllocator</phrase> <phrase role="special">&amp;&amp;</phrase> <phrase role="identifier">salloc</phrase><phrase role="special">,</phrase>
<phrase role="identifier">Fn</phrase> <phrase role="special">&amp;&amp;</phrase> <phrase role="identifier">fn</phrase><phrase role="special">,</phrase> <phrase role="identifier">Args</phrase> <phrase role="special">&amp;&amp;</phrase> <phrase role="special">...</phrase> <phrase role="identifier">args</phrase><phrase role="special">);</phrase>
</programlisting>
<variablelist>
<title></title>
<varlistentry>
<term>Preconditions:</term>
<listitem>
<para>
<code><phrase role="identifier">Fn</phrase></code> must be copyable
or movable.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>Effects:</term>
<listitem>
<para>
<code><phrase role="identifier">fn</phrase></code> is copied or moved
into internal storage for access by the new fiber. If <link linkend="class_launch"><code>launch</code></link> is
specified (or defaulted) to <code><phrase role="identifier">post</phrase></code>,
the new fiber is marked <quote>ready</quote> and will be entered at
the next opportunity. If <code><phrase role="identifier">launch</phrase></code>
is specified as <code><phrase role="identifier">dispatch</phrase></code>,
the calling fiber is suspended and the new fiber is entered immediately.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>Postconditions:</term>
<listitem>
<para>
<code><phrase role="special">*</phrase><phrase role="keyword">this</phrase></code>
refers to the newly created fiber of execution.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>Throws:</term>
<listitem>
<para>
<code><phrase role="identifier">fiber_error</phrase></code> if an error
occurs.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>Note:</term>
<listitem>
<para>
<link linkend="stack_allocator_concept"><code><phrase role="identifier">StackAllocator</phrase></code></link>
is required to allocate a stack for the internal __econtext__. If
<code><phrase role="identifier">StackAllocator</phrase></code> is not
explicitly passed, the default stack allocator depends on <code><phrase
role="identifier">BOOST_USE_SEGMENTED_STACKS</phrase></code>: if defined,
you will get a <link linkend="class_segmented_stack"><code>segmented_stack</code></link>, else a <link linkend="class_fixedsize_stack"><code>fixedsize_stack</code></link>.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>See also:</term>
<listitem>
<para>
<ulink url="http://en.cppreference.com/w/cpp/memory/allocator_arg_t"><code><phrase
role="identifier">std</phrase><phrase role="special">::</phrase><phrase
role="identifier">allocator_arg_t</phrase></code></ulink>, <link linkend="stack">Stack
allocation</link>
</para>
</listitem>
</varlistentry>
</variablelist>
<bridgehead renderas="sect4" id="fiber.fiber_mgmt.fiber.h2">
<phrase id="fiber.fiber_mgmt.fiber.move_constructor"/><link linkend="fiber.fiber_mgmt.fiber.move_constructor">Move
constructor</link>
</bridgehead>
<programlisting><phrase role="identifier">fiber</phrase><phrase role="special">(</phrase> <phrase role="identifier">fiber</phrase> <phrase role="special">&amp;&amp;</phrase> <phrase role="identifier">other</phrase><phrase role="special">)</phrase> <phrase role="keyword">noexcept</phrase><phrase role="special">;</phrase>
</programlisting>
<variablelist>
<title></title>
<varlistentry>
<term>Effects:</term>
<listitem>
<para>
Transfers ownership of the fiber managed by <code><phrase role="identifier">other</phrase></code>
to the newly constructed <link linkend="class_fiber"><code>fiber</code></link> instance.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>Postconditions:</term>
<listitem>
<para>
<code><phrase role="identifier">other</phrase><phrase role="special">.</phrase><phrase
role="identifier">get_id</phrase><phrase role="special">()</phrase>
<phrase role="special">==</phrase> <phrase role="identifier">fiber</phrase><phrase
role="special">::</phrase><phrase role="identifier">id</phrase><phrase
role="special">()</phrase></code> and <code><phrase role="identifier">get_id</phrase><phrase
role="special">()</phrase></code> returns the value of <code><phrase
role="identifier">other</phrase><phrase role="special">.</phrase><phrase
role="identifier">get_id</phrase><phrase role="special">()</phrase></code>
prior to the construction
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>Throws:</term>
<listitem>
<para>
Nothing
</para>
</listitem>
</varlistentry>
</variablelist>
<bridgehead renderas="sect4" id="fiber.fiber_mgmt.fiber.h3">
<phrase id="fiber.fiber_mgmt.fiber.move_assignment_operator"/><link linkend="fiber.fiber_mgmt.fiber.move_assignment_operator">Move
assignment operator</link>
</bridgehead>
<programlisting><phrase role="identifier">fiber</phrase> <phrase role="special">&amp;</phrase> <phrase role="keyword">operator</phrase><phrase role="special">=(</phrase> <phrase role="identifier">fiber</phrase> <phrase role="special">&amp;&amp;</phrase> <phrase role="identifier">other</phrase><phrase role="special">)</phrase> <phrase role="keyword">noexcept</phrase><phrase role="special">;</phrase>
</programlisting>
<variablelist>
<title></title>
<varlistentry>
<term>Effects:</term>
<listitem>
<para>
Transfers ownership of the fiber managed by <code><phrase role="identifier">other</phrase></code>
(if any) to <code><phrase role="special">*</phrase><phrase role="keyword">this</phrase></code>.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>Postconditions:</term>
<listitem>
<para>
<code><phrase role="identifier">other</phrase><phrase role="special">-&gt;</phrase><phrase
role="identifier">get_id</phrase><phrase role="special">()</phrase>
<phrase role="special">==</phrase> <phrase role="identifier">fiber</phrase><phrase
role="special">::</phrase><phrase role="identifier">id</phrase><phrase
role="special">()</phrase></code> and <code><phrase role="identifier">get_id</phrase><phrase
role="special">()</phrase></code> returns the value of <code><phrase
role="identifier">other</phrase><phrase role="special">.</phrase><phrase
role="identifier">get_id</phrase><phrase role="special">()</phrase></code>
prior to the assignment.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>Throws:</term>
<listitem>
<para>
Nothing
</para>
</listitem>
</varlistentry>
</variablelist>
<bridgehead renderas="sect4" id="fiber.fiber_mgmt.fiber.h4">
<phrase id="fiber.fiber_mgmt.fiber.destructor"/><link linkend="fiber.fiber_mgmt.fiber.destructor">Destructor</link>
</bridgehead>
<programlisting><phrase role="special">~</phrase><phrase role="identifier">fiber</phrase><phrase role="special">();</phrase>
</programlisting>
<variablelist>
<title></title>
<varlistentry>
<term>Effects:</term>
<listitem>
<para>
If the fiber is <link linkend="fiber_joinable"><code>fiber::joinable()</code></link>, calls std::terminate.
Destroys <code><phrase role="special">*</phrase><phrase role="keyword">this</phrase></code>.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>Note:</term>
<listitem>
<para>
The programmer must ensure that the destructor is never executed while
the fiber is still <link linkend="fiber_joinable"><code>fiber::joinable()</code></link>. Even if you know
that the fiber has completed, you must still call either <link linkend="fiber_join"><code>fiber::join()</code></link> or
<link linkend="fiber_detach"><code>fiber::detach()</code></link> before destroying the <code><phrase role="identifier">fiber</phrase></code>
object.
</para>
</listitem>
</varlistentry>
</variablelist>
<para>
<bridgehead renderas="sect4" id="fiber_joinable_bridgehead">
<phrase id="fiber_joinable"/>
<link linkend="fiber_joinable">Member function <code>joinable</code>()</link>
</bridgehead>
</para>
<programlisting><phrase role="keyword">bool</phrase> <phrase role="identifier">joinable</phrase><phrase role="special">()</phrase> <phrase role="keyword">const</phrase> <phrase role="keyword">noexcept</phrase><phrase role="special">;</phrase>
</programlisting>
<variablelist>
<title></title>
<varlistentry>
<term>Returns:</term>
<listitem>
<para>
<code><phrase role="keyword">true</phrase></code> if <code><phrase
role="special">*</phrase><phrase role="keyword">this</phrase></code>
refers to a fiber of execution, which may or may not have completed;
otherwise <code><phrase role="keyword">false</phrase></code>.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>Throws:</term>
<listitem>
<para>
Nothing
</para>
</listitem>
</varlistentry>
</variablelist>
<para>
<bridgehead renderas="sect4" id="fiber_join_bridgehead">
<phrase id="fiber_join"/>
<link linkend="fiber_join">Member function <code>join</code>()</link>
</bridgehead>
</para>
<programlisting><phrase role="keyword">void</phrase> <phrase role="identifier">join</phrase><phrase role="special">();</phrase>
</programlisting>
<variablelist>
<title></title>
<varlistentry>
<term>Preconditions:</term>
<listitem>
<para>
the fiber is <link linkend="fiber_joinable"><code>fiber::joinable()</code></link>.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>Effects:</term>
<listitem>
<para>
Waits for the referenced fiber of execution to complete.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>Postconditions:</term>
<listitem>
<para>
The fiber of execution referenced on entry has completed. <code><phrase
role="special">*</phrase><phrase role="keyword">this</phrase></code>
no longer refers to any fiber of execution.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>Throws:</term>
<listitem>
<para>
<code><phrase role="identifier">fiber_error</phrase></code>
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>Error Conditions:</term>
<listitem>
<para>
<emphasis role="bold">resource_deadlock_would_occur</emphasis>: if
<code><phrase role="keyword">this</phrase><phrase role="special">-&gt;</phrase><phrase
role="identifier">get_id</phrase><phrase role="special">()</phrase>
<phrase role="special">==</phrase> <phrase role="identifier">boost</phrase><phrase
role="special">::</phrase><phrase role="identifier">this_fiber</phrase><phrase
role="special">::</phrase><phrase role="identifier">get_id</phrase><phrase
role="special">()</phrase></code>. <emphasis role="bold">invalid_argument</emphasis>:
if the fiber is not <link linkend="fiber_joinable"><code>fiber::joinable()</code></link>.
</para>
</listitem>
</varlistentry>
</variablelist>
<para>
<bridgehead renderas="sect4" id="fiber_detach_bridgehead">
<phrase id="fiber_detach"/>
<link linkend="fiber_detach">Member function <code>detach</code>()</link>
</bridgehead>
</para>
<programlisting><phrase role="keyword">void</phrase> <phrase role="identifier">detach</phrase><phrase role="special">();</phrase>
</programlisting>
<variablelist>
<title></title>
<varlistentry>
<term>Preconditions:</term>
<listitem>
<para>
the fiber is <link linkend="fiber_joinable"><code>fiber::joinable()</code></link>.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>Effects:</term>
<listitem>
<para>
The fiber of execution becomes detached, and no longer has an associated
<link linkend="class_fiber"><code>fiber</code></link> object.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>Postconditions:</term>
<listitem>
<para>
<code><phrase role="special">*</phrase><phrase role="keyword">this</phrase></code>
no longer refers to any fiber of execution.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>Throws:</term>
<listitem>
<para>
<code><phrase role="identifier">fiber_error</phrase></code>
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>Error Conditions:</term>
<listitem>
<para>
<emphasis role="bold">invalid_argument</emphasis>: if the fiber is
not <link linkend="fiber_joinable"><code>fiber::joinable()</code></link>.
</para>
</listitem>
</varlistentry>
</variablelist>
<para>
<bridgehead renderas="sect4" id="fiber_get_id_bridgehead">
<phrase id="fiber_get_id"/>
<link linkend="fiber_get_id">Member function <code>get_id</code>()</link>
</bridgehead>
</para>
<programlisting><phrase role="identifier">fiber</phrase><phrase role="special">::</phrase><phrase role="identifier">id</phrase> <phrase role="identifier">get_id</phrase><phrase role="special">()</phrase> <phrase role="keyword">const</phrase> <phrase role="keyword">noexcept</phrase><phrase role="special">;</phrase>
</programlisting>
<variablelist>
<title></title>
<varlistentry>
<term>Returns:</term>
<listitem>
<para>
If <code><phrase role="special">*</phrase><phrase role="keyword">this</phrase></code>
refers to a fiber of execution, an instance of <link linkend="class_fiber_id"><code><phrase
role="identifier">fiber</phrase><phrase role="special">::</phrase><phrase
role="identifier">id</phrase></code></link> that represents that fiber. Otherwise
returns a default-constructed <link linkend="class_fiber_id"><code><phrase role="identifier">fiber</phrase><phrase
role="special">::</phrase><phrase role="identifier">id</phrase></code></link>.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>Throws:</term>
<listitem>
<para>
Nothing
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>See also:</term>
<listitem>
<para>
<link linkend="this_fiber_get_id"><code>this_fiber::get_id()</code></link>
</para>
</listitem>
</varlistentry>
</variablelist>
<para>
<bridgehead renderas="sect4" id="fiber_properties_bridgehead">
<phrase id="fiber_properties"/>
<link linkend="fiber_properties">Templated member
function <code>properties</code>()</link>
</bridgehead>
</para>
<programlisting><phrase role="keyword">template</phrase><phrase role="special">&lt;</phrase> <phrase role="keyword">typename</phrase> <phrase role="identifier">PROPS</phrase> <phrase role="special">&gt;</phrase>
<phrase role="identifier">PROPS</phrase> <phrase role="special">&amp;</phrase> <phrase role="identifier">properties</phrase><phrase role="special">();</phrase>
</programlisting>
<variablelist>
<title></title>
<varlistentry>
<term>Preconditions:</term>
<listitem>
<para>
<code><phrase role="special">*</phrase><phrase role="keyword">this</phrase></code>
refers to a fiber of execution. <link linkend="use_scheduling_algorithm"><code>use_scheduling_algorithm()</code></link> has
been called from this thread with a subclass of <link linkend="class_algorithm_with_properties"><code>algorithm_with_properties&lt;&gt;</code></link> with
the same template argument <code><phrase role="identifier">PROPS</phrase></code>.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>Returns:</term>
<listitem>
<para>
a reference to the scheduler properties instance for <code><phrase
role="special">*</phrase><phrase role="keyword">this</phrase></code>.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>Throws:</term>
<listitem>
<para>
<code><phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase
role="identifier">bad_cast</phrase></code> if <code><phrase role="identifier">use_scheduling_algorithm</phrase><phrase
role="special">()</phrase></code> was called with a <code><phrase role="identifier">algorithm_with_properties</phrase></code>
subclass with some other template parameter than <code><phrase role="identifier">PROPS</phrase></code>.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>Note:</term>
<listitem>
<para>
<link linkend="class_algorithm_with_properties"><code>algorithm_with_properties&lt;&gt;</code></link> provides
a way for a user-coded scheduler to associate extended properties,
such as priority, with a fiber instance. This method allows access
to those user-provided properties.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>See also:</term>
<listitem>
<para>
<link linkend="custom">Customization</link>
</para>
</listitem>
</varlistentry>
</variablelist>
<para>
<bridgehead renderas="sect4" id="fiber_swap_bridgehead">
<phrase id="fiber_swap"/>
<link linkend="fiber_swap">Member function <code>swap</code>()</link>
</bridgehead>
</para>
<programlisting><phrase role="keyword">void</phrase> <phrase role="identifier">swap</phrase><phrase role="special">(</phrase> <phrase role="identifier">fiber</phrase> <phrase role="special">&amp;</phrase> <phrase role="identifier">other</phrase><phrase role="special">)</phrase> <phrase role="keyword">noexcept</phrase><phrase role="special">;</phrase>
</programlisting>
<variablelist>
<title></title>
<varlistentry>
<term>Effects:</term>
<listitem>
<para>
Exchanges the fiber of execution associated with <code><phrase role="special">*</phrase><phrase
role="keyword">this</phrase></code> and <code><phrase role="identifier">other</phrase></code>,
so <code><phrase role="special">*</phrase><phrase role="keyword">this</phrase></code>
becomes associated with the fiber formerly associated with <code><phrase
role="identifier">other</phrase></code>, and vice-versa.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>Postconditions:</term>
<listitem>
<para>
<code><phrase role="keyword">this</phrase><phrase role="special">-&gt;</phrase><phrase
role="identifier">get_id</phrase><phrase role="special">()</phrase></code>
returns the same value as <code><phrase role="identifier">other</phrase><phrase
role="special">.</phrase><phrase role="identifier">get_id</phrase><phrase
role="special">()</phrase></code> prior to the call. <code><phrase
role="identifier">other</phrase><phrase role="special">.</phrase><phrase
role="identifier">get_id</phrase><phrase role="special">()</phrase></code>
returns the same value as <code><phrase role="keyword">this</phrase><phrase
role="special">-&gt;</phrase><phrase role="identifier">get_id</phrase><phrase
role="special">()</phrase></code> prior to the call.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>Throws:</term>
<listitem>
<para>
Nothing
</para>
</listitem>
</varlistentry>
</variablelist>
<para>
<bridgehead renderas="sect4" id="swap_for_fiber_bridgehead">
<phrase id="swap_for_fiber"/>
<link linkend="swap_for_fiber">Non-member function
<code>swap()</code></link>
</bridgehead>
</para>
<programlisting><phrase role="keyword">void</phrase> <phrase role="identifier">swap</phrase><phrase role="special">(</phrase> <phrase role="identifier">fiber</phrase> <phrase role="special">&amp;</phrase> <phrase role="identifier">l</phrase><phrase role="special">,</phrase> <phrase role="identifier">fiber</phrase> <phrase role="special">&amp;</phrase> <phrase role="identifier">r</phrase><phrase role="special">)</phrase> <phrase role="keyword">noexcept</phrase><phrase role="special">;</phrase>
</programlisting>
<variablelist>
<title></title>
<varlistentry>
<term>Effects:</term>
<listitem>
<para>
Same as <code><phrase role="identifier">l</phrase><phrase role="special">.</phrase><phrase
role="identifier">swap</phrase><phrase role="special">(</phrase> <phrase
role="identifier">r</phrase><phrase role="special">)</phrase></code>.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>Throws:</term>
<listitem>
<para>
Nothing
</para>
</listitem>
</varlistentry>
</variablelist>
<para>
<bridgehead renderas="sect4" id="operator&lt;_bridgehead">
<phrase id="operator&lt;"/>
<link linkend="operator&lt;">Non-member function <code>operator&lt;()</code></link>
</bridgehead>
</para>
<programlisting><phrase role="keyword">bool</phrase> <phrase role="keyword">operator</phrase><phrase role="special">&lt;(</phrase> <phrase role="identifier">fiber</phrase> <phrase role="keyword">const</phrase><phrase role="special">&amp;</phrase> <phrase role="identifier">l</phrase><phrase role="special">,</phrase> <phrase role="identifier">fiber</phrase> <phrase role="keyword">const</phrase><phrase role="special">&amp;</phrase> <phrase role="identifier">r</phrase><phrase role="special">)</phrase> <phrase role="keyword">noexcept</phrase><phrase role="special">;</phrase>
</programlisting>
<variablelist>
<title></title>
<varlistentry>
<term>Returns:</term>
<listitem>
<para>
<code><phrase role="keyword">true</phrase></code> if <code><phrase
role="identifier">l</phrase><phrase role="special">.</phrase><phrase
role="identifier">get_id</phrase><phrase role="special">()</phrase>
<phrase role="special">&lt;</phrase> <phrase role="identifier">r</phrase><phrase
role="special">.</phrase><phrase role="identifier">get_id</phrase><phrase
role="special">()</phrase></code> is <code><phrase role="keyword">true</phrase></code>,
false otherwise.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>Throws:</term>
<listitem>
<para>
Nothing.
</para>
</listitem>
</varlistentry>
</variablelist>
<para>
<bridgehead renderas="sect4" id="use_scheduling_algorithm_bridgehead">
<phrase id="use_scheduling_algorithm"/>
<link linkend="use_scheduling_algorithm">Non-member
function <code>use_scheduling_algorithm()</code></link>
</bridgehead>
</para>
<programlisting><phrase role="keyword">template</phrase><phrase role="special">&lt;</phrase> <phrase role="keyword">typename</phrase> <phrase role="identifier">SchedAlgo</phrase><phrase role="special">,</phrase> <phrase role="keyword">typename</phrase> <phrase role="special">...</phrase> <phrase role="identifier">Args</phrase> <phrase role="special">&gt;</phrase>
<phrase role="keyword">void</phrase> <phrase role="identifier">use_scheduling_algorithm</phrase><phrase role="special">(</phrase> <phrase role="identifier">Args</phrase> <phrase role="special">&amp;&amp;</phrase> <phrase role="special">...</phrase> <phrase role="identifier">args</phrase><phrase role="special">)</phrase> <phrase role="keyword">noexcept</phrase><phrase role="special">;</phrase>
</programlisting>
<variablelist>
<title></title>
<varlistentry>
<term>Effects:</term>
<listitem>
<para>
Directs <emphasis role="bold">Boost.Fiber</emphasis> to use <code><phrase
role="identifier">SchedAlgo</phrase></code>, which must be a concrete
subclass of <link linkend="class_algorithm"><code>algorithm</code></link>, as the scheduling algorithm for
all fibers in the current thread. Pass any required <code><phrase role="identifier">SchedAlgo</phrase></code>
constructor arguments as <code><phrase role="identifier">args</phrase></code>.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>Note:</term>
<listitem>
<para>
If you want a given thread to use a non-default scheduling algorithm,
make that thread call <code><phrase role="identifier">use_scheduling_algorithm</phrase><phrase
role="special">()</phrase></code> before any other <emphasis role="bold">Boost.Fiber</emphasis>
entry point. If no scheduler has been set for the current thread by
the time <emphasis role="bold">Boost.Fiber</emphasis> needs to use
it, the library will create a default <link linkend="class_round_robin"><code>round_robin</code></link> instance
for this thread.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>Throws:</term>
<listitem>
<para>
Nothing
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>See also:</term>
<listitem>
<para>
<link linkend="scheduling">Scheduling</link>, <link linkend="custom">Customization</link>
</para>
</listitem>
</varlistentry>
</variablelist>
<para>
<bridgehead renderas="sect4" id="has_ready_fibers_bridgehead">
<phrase id="has_ready_fibers"/>
<link linkend="has_ready_fibers">Non-member function
<code>has_ready_fibers()</code></link>
</bridgehead>
</para>
<programlisting><phrase role="keyword">bool</phrase> <phrase role="identifier">has_ready_fibers</phrase><phrase role="special">()</phrase> <phrase role="keyword">noexcept</phrase><phrase role="special">;</phrase>
</programlisting>
<variablelist>
<title></title>
<varlistentry>
<term>Returns:</term>
<listitem>
<para>
<code><phrase role="keyword">true</phrase></code> if scheduler has
fibers ready to run.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>Throws:</term>
<listitem>
<para>
Nothing
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>Note:</term>
<listitem>
<para>
Can be used for work-stealing to find an idle scheduler.
</para>
</listitem>
</varlistentry>
</variablelist>
</section>
<section id="fiber.fiber_mgmt.id">
<title><anchor id="class_id"/><link linkend="fiber.fiber_mgmt.id">Class fiber::id</link></title>
<programlisting><phrase role="preprocessor">#include</phrase> <phrase role="special">&lt;</phrase><phrase role="identifier">boost</phrase><phrase role="special">/</phrase><phrase role="identifier">fiber</phrase><phrase role="special">/</phrase><phrase role="identifier">fiber</phrase><phrase role="special">.</phrase><phrase role="identifier">hpp</phrase><phrase role="special">&gt;</phrase>
<phrase role="keyword">namespace</phrase> <phrase role="identifier">boost</phrase> <phrase role="special">{</phrase>
<phrase role="keyword">namespace</phrase> <phrase role="identifier">fibers</phrase> <phrase role="special">{</phrase>
<phrase role="keyword">class</phrase> <phrase role="identifier">id</phrase> <phrase role="special">{</phrase>
<phrase role="keyword">public</phrase><phrase role="special">:</phrase>
<phrase role="keyword">constexpr</phrase> <phrase role="identifier">id</phrase><phrase role="special">()</phrase> <phrase role="keyword">noexcept</phrase><phrase role="special">;</phrase>
<phrase role="keyword">bool</phrase> <phrase role="keyword">operator</phrase><phrase role="special">==(</phrase> <phrase role="identifier">id</phrase> <phrase role="keyword">const</phrase><phrase role="special">&amp;)</phrase> <phrase role="keyword">const</phrase> <phrase role="keyword">noexcept</phrase><phrase role="special">;</phrase>
<phrase role="keyword">bool</phrase> <phrase role="keyword">operator</phrase><phrase role="special">!=(</phrase> <phrase role="identifier">id</phrase> <phrase role="keyword">const</phrase><phrase role="special">&amp;)</phrase> <phrase role="keyword">const</phrase> <phrase role="keyword">noexcept</phrase><phrase role="special">;</phrase>
<phrase role="keyword">bool</phrase> <phrase role="keyword">operator</phrase><phrase role="special">&lt;(</phrase> <phrase role="identifier">id</phrase> <phrase role="keyword">const</phrase><phrase role="special">&amp;)</phrase> <phrase role="keyword">const</phrase> <phrase role="keyword">noexcept</phrase><phrase role="special">;</phrase>
<phrase role="keyword">bool</phrase> <phrase role="keyword">operator</phrase><phrase role="special">&gt;(</phrase> <phrase role="identifier">id</phrase> <phrase role="keyword">const</phrase><phrase role="special">&amp;)</phrase> <phrase role="keyword">const</phrase> <phrase role="keyword">noexcept</phrase><phrase role="special">;</phrase>
<phrase role="keyword">bool</phrase> <phrase role="keyword">operator</phrase><phrase role="special">&lt;=(</phrase> <phrase role="identifier">id</phrase> <phrase role="keyword">const</phrase><phrase role="special">&amp;)</phrase> <phrase role="keyword">const</phrase> <phrase role="keyword">noexcept</phrase><phrase role="special">;</phrase>
<phrase role="keyword">bool</phrase> <phrase role="keyword">operator</phrase><phrase role="special">&gt;=(</phrase> <phrase role="identifier">id</phrase> <phrase role="keyword">const</phrase><phrase role="special">&amp;)</phrase> <phrase role="keyword">const</phrase> <phrase role="keyword">noexcept</phrase><phrase role="special">;</phrase>
<phrase role="keyword">template</phrase><phrase role="special">&lt;</phrase> <phrase role="keyword">typename</phrase> <phrase role="identifier">charT</phrase><phrase role="special">,</phrase> <phrase role="keyword">class</phrase> <phrase role="identifier">traitsT</phrase> <phrase role="special">&gt;</phrase>
<phrase role="keyword">friend</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">basic_ostream</phrase><phrase role="special">&lt;</phrase> <phrase role="identifier">charT</phrase><phrase role="special">,</phrase> <phrase role="identifier">traitsT</phrase> <phrase role="special">&gt;</phrase> <phrase role="special">&amp;</phrase>
<phrase role="keyword">operator</phrase><phrase role="special">&lt;&lt;(</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">basic_ostream</phrase><phrase role="special">&lt;</phrase> <phrase role="identifier">charT</phrase><phrase role="special">,</phrase> <phrase role="identifier">traitsT</phrase> <phrase role="special">&gt;</phrase> <phrase role="special">&amp;,</phrase> <phrase role="identifier">id</phrase> <phrase role="keyword">const</phrase><phrase role="special">&amp;);</phrase>
<phrase role="special">};</phrase>
<phrase role="special">}}</phrase>
</programlisting>
<bridgehead renderas="sect4" id="fiber.fiber_mgmt.id.h0">
<phrase id="fiber.fiber_mgmt.id.constructor"/><link linkend="fiber.fiber_mgmt.id.constructor">Constructor</link>
</bridgehead>
<programlisting><phrase role="keyword">constexpr</phrase> <phrase role="identifier">id</phrase><phrase role="special">()</phrase> <phrase role="keyword">noexcept</phrase><phrase role="special">;</phrase>
</programlisting>
<variablelist>
<title></title>
<varlistentry>
<term>Effects:</term>
<listitem>
<para>
Represents an instance of <emphasis>not-a-fiber</emphasis>.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>Throws:</term>
<listitem>
<para>
Nothing.
</para>
</listitem>
</varlistentry>
</variablelist>
<para>
<bridgehead renderas="sect4" id="id_operator_equal_bridgehead">
<phrase id="id_operator_equal"/>
<link linkend="id_operator_equal">Member function
<code>operator==</code>()</link>
</bridgehead>
</para>
<programlisting><phrase role="keyword">bool</phrase> <phrase role="keyword">operator</phrase><phrase role="special">==(</phrase> <phrase role="identifier">id</phrase> <phrase role="keyword">const</phrase><phrase role="special">&amp;</phrase> <phrase role="identifier">other</phrase><phrase role="special">)</phrase> <phrase role="keyword">const</phrase> <phrase role="keyword">noexcept</phrase><phrase role="special">;</phrase>
</programlisting>
<variablelist>
<title></title>
<varlistentry>
<term>Returns:</term>
<listitem>
<para>
<code><phrase role="keyword">true</phrase></code> if <code><phrase
role="special">*</phrase><phrase role="keyword">this</phrase></code>
and <code><phrase role="identifier">other</phrase></code> represent
the same fiber, or both represent <emphasis>not-a-fiber</emphasis>,
<code><phrase role="keyword">false</phrase></code> otherwise.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>Throws:</term>
<listitem>
<para>
Nothing.
</para>
</listitem>
</varlistentry>
</variablelist>
<para>
<bridgehead renderas="sect4" id="id_operator_not_equal_bridgehead">
<phrase id="id_operator_not_equal"/>
<link linkend="id_operator_not_equal">Member
function <code>operator!=</code>()</link>
</bridgehead>
</para>
<programlisting><phrase role="keyword">bool</phrase> <phrase role="keyword">operator</phrase><phrase role="special">!=(</phrase> <phrase role="identifier">id</phrase> <phrase role="keyword">const</phrase><phrase role="special">&amp;</phrase> <phrase role="identifier">other</phrase><phrase role="special">)</phrase> <phrase role="keyword">const</phrase> <phrase role="keyword">noexcept</phrase><phrase role="special">;</phrase>
</programlisting>
<variablelist>
<title></title>
<varlistentry>
<term>Returns:</term>
<listitem>
<para>
<code>! (other == * this)</code>
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>Throws:</term>
<listitem>
<para>
Nothing.
</para>
</listitem>
</varlistentry>
</variablelist>
<para>
<bridgehead renderas="sect4" id="id_operator_less_bridgehead">
<phrase id="id_operator_less"/>
<link linkend="id_operator_less">Member function
<code>operator&lt;</code>()</link>
</bridgehead>
</para>
<programlisting><phrase role="keyword">bool</phrase> <phrase role="keyword">operator</phrase><phrase role="special">&lt;(</phrase> <phrase role="identifier">id</phrase> <phrase role="keyword">const</phrase><phrase role="special">&amp;</phrase> <phrase role="identifier">other</phrase><phrase role="special">)</phrase> <phrase role="keyword">const</phrase> <phrase role="keyword">noexcept</phrase><phrase role="special">;</phrase>
</programlisting>
<variablelist>
<title></title>
<varlistentry>
<term>Returns:</term>
<listitem>
<para>
<code><phrase role="keyword">true</phrase></code> if <code><phrase
role="special">*</phrase><phrase role="keyword">this</phrase> <phrase
role="special">!=</phrase> <phrase role="identifier">other</phrase></code>
is true and the implementation-defined total order of <code><phrase
role="identifier">fiber</phrase><phrase role="special">::</phrase><phrase
role="identifier">id</phrase></code> values places <code><phrase role="special">*</phrase><phrase
role="keyword">this</phrase></code> before <code><phrase role="identifier">other</phrase></code>,
false otherwise.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>Throws:</term>
<listitem>
<para>
Nothing.
</para>
</listitem>
</varlistentry>
</variablelist>
<para>
<bridgehead renderas="sect4" id="id_operator_greater_bridgehead">
<phrase id="id_operator_greater"/>
<link linkend="id_operator_greater">Member
function <code>operator&gt;</code>()</link>
</bridgehead>
</para>
<programlisting><phrase role="keyword">bool</phrase> <phrase role="keyword">operator</phrase><phrase role="special">&gt;(</phrase> <phrase role="identifier">id</phrase> <phrase role="keyword">const</phrase><phrase role="special">&amp;</phrase> <phrase role="identifier">other</phrase><phrase role="special">)</phrase> <phrase role="keyword">const</phrase> <phrase role="keyword">noexcept</phrase><phrase role="special">;</phrase>
</programlisting>
<variablelist>
<title></title>
<varlistentry>
<term>Returns:</term>
<listitem>
<para>
<code><phrase role="identifier">other</phrase> <phrase role="special">&lt;</phrase>
<phrase role="special">*</phrase> <phrase role="keyword">this</phrase></code>
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>Throws:</term>
<listitem>
<para>
Nothing.
</para>
</listitem>
</varlistentry>
</variablelist>
<para>
<bridgehead renderas="sect4" id="id_operator_less_equal_bridgehead">
<phrase id="id_operator_less_equal"/>
<link linkend="id_operator_less_equal">Member
function <code>operator&lt;=</code>()</link>
</bridgehead>
</para>
<programlisting><phrase role="keyword">bool</phrase> <phrase role="keyword">operator</phrase><phrase role="special">&lt;=(</phrase> <phrase role="identifier">id</phrase> <phrase role="keyword">const</phrase><phrase role="special">&amp;</phrase> <phrase role="identifier">other</phrase><phrase role="special">)</phrase> <phrase role="keyword">const</phrase> <phrase role="keyword">noexcept</phrase><phrase role="special">;</phrase>
</programlisting>
<variablelist>
<title></title>
<varlistentry>
<term>Returns:</term>
<listitem>
<para>
<code><phrase role="special">!</phrase> <phrase role="special">(</phrase><phrase
role="identifier">other</phrase> <phrase role="special">&lt;</phrase>
<phrase role="special">*</phrase> <phrase role="keyword">this</phrase><phrase
role="special">)</phrase></code>
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>Throws:</term>
<listitem>
<para>
Nothing.
</para>
</listitem>
</varlistentry>
</variablelist>
<para>
<bridgehead renderas="sect4" id="id_operator_greater_equal_bridgehead">
<phrase id="id_operator_greater_equal"/>
<link linkend="id_operator_greater_equal">Member
function <code>operator&gt;=</code>()</link>
</bridgehead>
</para>
<programlisting><phrase role="keyword">bool</phrase> <phrase role="keyword">operator</phrase><phrase role="special">&gt;=(</phrase> <phrase role="identifier">id</phrase> <phrase role="keyword">const</phrase><phrase role="special">&amp;</phrase> <phrase role="identifier">other</phrase><phrase role="special">)</phrase> <phrase role="keyword">const</phrase> <phrase role="keyword">noexcept</phrase><phrase role="special">;</phrase>
</programlisting>
<variablelist>
<title></title>
<varlistentry>
<term>Returns:</term>
<listitem>
<para>
<code><phrase role="special">!</phrase> <phrase role="special">(*</phrase>
<phrase role="keyword">this</phrase> <phrase role="special">&lt;</phrase>
<phrase role="identifier">other</phrase><phrase role="special">)</phrase></code>
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>Throws:</term>
<listitem>
<para>
Nothing.
</para>
</listitem>
</varlistentry>
</variablelist>
<bridgehead renderas="sect4" id="fiber.fiber_mgmt.id.h1">
<phrase id="fiber.fiber_mgmt.id.operator_lt__lt_"/><link linkend="fiber.fiber_mgmt.id.operator_lt__lt_">operator&lt;&lt;</link>
</bridgehead>
<programlisting><phrase role="keyword">template</phrase><phrase role="special">&lt;</phrase> <phrase role="keyword">typename</phrase> <phrase role="identifier">charT</phrase><phrase role="special">,</phrase> <phrase role="keyword">class</phrase> <phrase role="identifier">traitsT</phrase> <phrase role="special">&gt;</phrase>
<phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">basic_ostream</phrase><phrase role="special">&lt;</phrase> <phrase role="identifier">charT</phrase><phrase role="special">,</phrase> <phrase role="identifier">traitsT</phrase> <phrase role="special">&gt;</phrase> <phrase role="special">&amp;</phrase>
<phrase role="keyword">operator</phrase><phrase role="special">&lt;&lt;(</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">basic_ostream</phrase><phrase role="special">&lt;</phrase> <phrase role="identifier">charT</phrase><phrase role="special">,</phrase> <phrase role="identifier">traitsT</phrase> <phrase role="special">&gt;</phrase> <phrase role="special">&amp;</phrase> <phrase role="identifier">os</phrase><phrase role="special">,</phrase> <phrase role="identifier">id</phrase> <phrase role="keyword">const</phrase><phrase role="special">&amp;</phrase> <phrase role="identifier">other</phrase><phrase role="special">);</phrase>
</programlisting>
<variablelist>
<title></title>
<varlistentry>
<term>Efects:</term>
<listitem>
<para>
Writes the representation of <code><phrase role="identifier">other</phrase></code>
to stream <code><phrase role="identifier">os</phrase></code>. The representation
is unspecified.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>Returns:</term>
<listitem>
<para>
<code><phrase role="identifier">os</phrase></code>
</para>
</listitem>
</varlistentry>
</variablelist>
</section>
<section id="fiber.fiber_mgmt.this_fiber">
<title><link linkend="fiber.fiber_mgmt.this_fiber">Namespace this_fiber</link></title>
<para>
In general, <code><phrase role="identifier">this_fiber</phrase></code> operations
may be called from the <quote>main</quote> fiber &mdash; the fiber on which function
<code><phrase role="identifier">main</phrase><phrase role="special">()</phrase></code>
is entered &mdash; as well as from an explicitly-launched thread&#8217;s thread-function.
That is, in many respects the main fiber on each thread can be treated like
an explicitly-launched fiber.
</para>
<programlisting><phrase role="keyword">namespace</phrase> <phrase role="identifier">boost</phrase> <phrase role="special">{</phrase>
<phrase role="keyword">namespace</phrase> <phrase role="identifier">this_fiber</phrase> <phrase role="special">{</phrase>
<phrase role="identifier">fibers</phrase><phrase role="special">::</phrase><phrase role="identifier">fiber</phrase><phrase role="special">::</phrase><phrase role="identifier">id</phrase> <phrase role="identifier">get_id</phrase><phrase role="special">()</phrase> <phrase role="keyword">noexcept</phrase><phrase role="special">;</phrase>
<phrase role="keyword">void</phrase> <phrase role="identifier">yield</phrase><phrase role="special">()</phrase> <phrase role="keyword">noexcept</phrase><phrase role="special">;</phrase>
<phrase role="keyword">template</phrase><phrase role="special">&lt;</phrase> <phrase role="keyword">typename</phrase> <phrase role="identifier">Clock</phrase><phrase role="special">,</phrase> <phrase role="keyword">typename</phrase> <phrase role="identifier">Duration</phrase> <phrase role="special">&gt;</phrase>
<phrase role="keyword">void</phrase> <phrase role="identifier">sleep_until</phrase><phrase role="special">(</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">chrono</phrase><phrase role="special">::</phrase><phrase role="identifier">time_point</phrase><phrase role="special">&lt;</phrase> <phrase role="identifier">Clock</phrase><phrase role="special">,</phrase> <phrase role="identifier">Duration</phrase> <phrase role="special">&gt;</phrase> <phrase role="keyword">const</phrase><phrase role="special">&amp;);</phrase>
<phrase role="keyword">template</phrase><phrase role="special">&lt;</phrase> <phrase role="keyword">typename</phrase> <phrase role="identifier">Rep</phrase><phrase role="special">,</phrase> <phrase role="keyword">typename</phrase> <phrase role="identifier">Period</phrase> <phrase role="special">&gt;</phrase>
<phrase role="keyword">void</phrase> <phrase role="identifier">sleep_for</phrase><phrase role="special">(</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">chrono</phrase><phrase role="special">::</phrase><phrase role="identifier">duration</phrase><phrase role="special">&lt;</phrase> <phrase role="identifier">Rep</phrase><phrase role="special">,</phrase> <phrase role="identifier">Period</phrase> <phrase role="special">&gt;</phrase> <phrase role="keyword">const</phrase><phrase role="special">&amp;);</phrase>
<phrase role="keyword">template</phrase><phrase role="special">&lt;</phrase> <phrase role="keyword">typename</phrase> <phrase role="identifier">PROPS</phrase> <phrase role="special">&gt;</phrase>
<phrase role="identifier">PROPS</phrase> <phrase role="special">&amp;</phrase> <phrase role="identifier">properties</phrase><phrase role="special">();</phrase>
<phrase role="special">}}</phrase>
</programlisting>
<para>
<bridgehead renderas="sect4" id="this_fiber_get_id_bridgehead">
<phrase id="this_fiber_get_id"/>
<link linkend="this_fiber_get_id">Non-member
function <code>this_fiber::get_id()</code></link>
</bridgehead>
</para>
<programlisting><phrase role="preprocessor">#include</phrase> <phrase role="special">&lt;</phrase><phrase role="identifier">boost</phrase><phrase role="special">/</phrase><phrase role="identifier">fiber</phrase><phrase role="special">/</phrase><phrase role="identifier">operations</phrase><phrase role="special">.</phrase><phrase role="identifier">hpp</phrase><phrase role="special">&gt;</phrase>
<phrase role="keyword">namespace</phrase> <phrase role="identifier">boost</phrase> <phrase role="special">{</phrase>
<phrase role="keyword">namespace</phrase> <phrase role="identifier">fibers</phrase> <phrase role="special">{</phrase>
<phrase role="identifier">fiber</phrase><phrase role="special">::</phrase><phrase role="identifier">id</phrase> <phrase role="identifier">get_id</phrase><phrase role="special">()</phrase> <phrase role="keyword">noexcept</phrase><phrase role="special">;</phrase>
<phrase role="special">}}</phrase>
</programlisting>
<variablelist>
<title></title>
<varlistentry>
<term>Returns:</term>
<listitem>
<para>
An instance of <link linkend="class_fiber_id"><code><phrase role="identifier">fiber</phrase><phrase
role="special">::</phrase><phrase role="identifier">id</phrase></code></link> that
represents the currently executing fiber.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>Throws:</term>
<listitem>
<para>
Nothing.
</para>
</listitem>
</varlistentry>
</variablelist>
<para>
<bridgehead renderas="sect4" id="this_fiber_sleep_until_bridgehead">
<phrase id="this_fiber_sleep_until"/>
<link linkend="this_fiber_sleep_until">Non-member
function <code>this_fiber::sleep_until()</code></link>
</bridgehead>
</para>
<programlisting><phrase role="preprocessor">#include</phrase> <phrase role="special">&lt;</phrase><phrase role="identifier">boost</phrase><phrase role="special">/</phrase><phrase role="identifier">fiber</phrase><phrase role="special">/</phrase><phrase role="identifier">operations</phrase><phrase role="special">.</phrase><phrase role="identifier">hpp</phrase><phrase role="special">&gt;</phrase>
<phrase role="keyword">namespace</phrase> <phrase role="identifier">boost</phrase> <phrase role="special">{</phrase>
<phrase role="keyword">namespace</phrase> <phrase role="identifier">fibers</phrase> <phrase role="special">{</phrase>
<phrase role="keyword">template</phrase><phrase role="special">&lt;</phrase> <phrase role="keyword">typename</phrase> <phrase role="identifier">Clock</phrase><phrase role="special">,</phrase> <phrase role="keyword">typename</phrase> <phrase role="identifier">Duration</phrase> <phrase role="special">&gt;</phrase>
<phrase role="keyword">void</phrase> <phrase role="identifier">sleep_until</phrase><phrase role="special">(</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">chrono</phrase><phrase role="special">::</phrase><phrase role="identifier">time_point</phrase><phrase role="special">&lt;</phrase> <phrase role="identifier">Clock</phrase><phrase role="special">,</phrase> <phrase role="identifier">Duration</phrase> <phrase role="special">&gt;</phrase> <phrase role="keyword">const</phrase><phrase role="special">&amp;</phrase> <phrase role="identifier">abs_time</phrase><phrase role="special">);</phrase>
<phrase role="special">}}</phrase>
</programlisting>
<variablelist>
<title></title>
<varlistentry>
<term>Effects:</term>
<listitem>
<para>
Suspends the current fiber until the time point specified by <code><phrase
role="identifier">abs_time</phrase></code> has been reached.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>Throws:</term>
<listitem>
<para>
timeout-related exceptions.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>Note:</term>
<listitem>
<para>
The current fiber will not resume before <code><phrase role="identifier">abs_time</phrase></code>,
but there are no guarantees about how soon after <code><phrase role="identifier">abs_time</phrase></code>
it might resume.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>Note:</term>
<listitem>
<para>
<quote>timeout-related exceptions</quote> are as defined in the C++
Standard, section <emphasis role="bold">30.2.4 Timing specifications
[thread.req.timing]</emphasis>: <quote>A function that takes an argument
which specifies a timeout will throw if, during its execution, a clock,
time point, or time duration throws an exception. Such exceptions are
referred to as <emphasis>timeout-related exceptions.</emphasis></quote>
</para>
</listitem>
</varlistentry>
</variablelist>
<para>
<bridgehead renderas="sect4" id="this_fiber_sleep_for_bridgehead">
<phrase id="this_fiber_sleep_for"/>
<link linkend="this_fiber_sleep_for">Non-member
function <code>this_fiber::sleep_for()</code></link>
</bridgehead>
</para>
<programlisting><phrase role="preprocessor">#include</phrase> <phrase role="special">&lt;</phrase><phrase role="identifier">boost</phrase><phrase role="special">/</phrase><phrase role="identifier">fiber</phrase><phrase role="special">/</phrase><phrase role="identifier">operations</phrase><phrase role="special">.</phrase><phrase role="identifier">hpp</phrase><phrase role="special">&gt;</phrase>
<phrase role="keyword">namespace</phrase> <phrase role="identifier">boost</phrase> <phrase role="special">{</phrase>
<phrase role="keyword">namespace</phrase> <phrase role="identifier">fibers</phrase> <phrase role="special">{</phrase>
<phrase role="keyword">template</phrase><phrase role="special">&lt;</phrase> <phrase role="keyword">class</phrase> <phrase role="identifier">Rep</phrase><phrase role="special">,</phrase> <phrase role="keyword">class</phrase> <phrase role="identifier">Period</phrase> <phrase role="special">&gt;</phrase>
<phrase role="keyword">void</phrase> <phrase role="identifier">sleep_for</phrase><phrase role="special">(</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">chrono</phrase><phrase role="special">::</phrase><phrase role="identifier">duration</phrase><phrase role="special">&lt;</phrase> <phrase role="identifier">Rep</phrase><phrase role="special">,</phrase> <phrase role="identifier">Period</phrase> <phrase role="special">&gt;</phrase> <phrase role="keyword">const</phrase><phrase role="special">&amp;</phrase> <phrase role="identifier">rel_time</phrase><phrase role="special">);</phrase>
<phrase role="special">}}</phrase>
</programlisting>
<variablelist>
<title></title>
<varlistentry>
<term>Effects:</term>
<listitem>
<para>
Suspends the current fiber until the time duration specified by <code><phrase
role="identifier">rel_time</phrase></code> has elapsed.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>Throws:</term>
<listitem>
<para>
timeout-related exceptions.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>Note:</term>
<listitem>
<para>
The current fiber will not resume before <code><phrase role="identifier">rel_time</phrase></code>
has elapsed, but there are no guarantees about how soon after that
it might resume.
</para>
</listitem>
</varlistentry>
</variablelist>
<para>
<bridgehead renderas="sect4" id="this_fiber_yield_bridgehead">
<phrase id="this_fiber_yield"/>
<link linkend="this_fiber_yield">Non-member function
<code>this_fiber::yield()</code></link>
</bridgehead>
</para>
<programlisting><phrase role="preprocessor">#include</phrase> <phrase role="special">&lt;</phrase><phrase role="identifier">boost</phrase><phrase role="special">/</phrase><phrase role="identifier">fiber</phrase><phrase role="special">/</phrase><phrase role="identifier">operations</phrase><phrase role="special">.</phrase><phrase role="identifier">hpp</phrase><phrase role="special">&gt;</phrase>
<phrase role="keyword">namespace</phrase> <phrase role="identifier">boost</phrase> <phrase role="special">{</phrase>
<phrase role="keyword">namespace</phrase> <phrase role="identifier">fibers</phrase> <phrase role="special">{</phrase>
<phrase role="keyword">void</phrase> <phrase role="identifier">yield</phrase><phrase role="special">()</phrase> <phrase role="keyword">noexcept</phrase><phrase role="special">;</phrase>
<phrase role="special">}}</phrase>
</programlisting>
<variablelist>
<title></title>
<varlistentry>
<term>Effects:</term>
<listitem>
<para>
Relinquishes execution control, allowing other fibers to run.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>Throws:</term>
<listitem>
<para>
Nothing.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>Note:</term>
<listitem>
<para>
A fiber that calls <code><phrase role="identifier">yield</phrase><phrase
role="special">()</phrase></code> is not suspended: it is immediately
passed to the scheduler as ready to run.
</para>
</listitem>
</varlistentry>
</variablelist>
<para>
<bridgehead renderas="sect4" id="this_fiber_properties_bridgehead">
<phrase id="this_fiber_properties"/>
<link linkend="this_fiber_properties">Non-member
function <code>this_fiber::properties()</code></link>
</bridgehead>
</para>
<programlisting><phrase role="preprocessor">#include</phrase> <phrase role="special">&lt;</phrase><phrase role="identifier">boost</phrase><phrase role="special">/</phrase><phrase role="identifier">fiber</phrase><phrase role="special">/</phrase><phrase role="identifier">operations</phrase><phrase role="special">.</phrase><phrase role="identifier">hpp</phrase><phrase role="special">&gt;</phrase>
<phrase role="keyword">namespace</phrase> <phrase role="identifier">boost</phrase> <phrase role="special">{</phrase>
<phrase role="keyword">namespace</phrase> <phrase role="identifier">fibers</phrase> <phrase role="special">{</phrase>
<phrase role="keyword">template</phrase><phrase role="special">&lt;</phrase> <phrase role="keyword">typename</phrase> <phrase role="identifier">PROPS</phrase> <phrase role="special">&gt;</phrase>
<phrase role="identifier">PROPS</phrase> <phrase role="special">&amp;</phrase> <phrase role="identifier">properties</phrase><phrase role="special">();</phrase>
<phrase role="special">}}</phrase>
</programlisting>
<variablelist>
<title></title>
<varlistentry>
<term>Preconditions:</term>
<listitem>
<para>
<link linkend="use_scheduling_algorithm"><code>use_scheduling_algorithm()</code></link> has been called from
this thread with a subclass of <link linkend="class_algorithm_with_properties"><code>algorithm_with_properties&lt;&gt;</code></link> with
the same template argument <code><phrase role="identifier">PROPS</phrase></code>.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>Returns:</term>
<listitem>
<para>
a reference to the scheduler properties instance for the currently
running fiber.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>Throws:</term>
<listitem>
<para>
<code><phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase
role="identifier">bad_cast</phrase></code> if <code><phrase role="identifier">use_scheduling_algorithm</phrase><phrase
role="special">()</phrase></code> was called with an <code><phrase
role="identifier">algorithm_with_properties</phrase></code> subclass
with some other template parameter than <code><phrase role="identifier">PROPS</phrase></code>.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>Note:</term>
<listitem>
<para>
<link linkend="class_algorithm_with_properties"><code>algorithm_with_properties&lt;&gt;</code></link> provides
a way for a user-coded scheduler to associate extended properties,
such as priority, with a fiber instance. This function allows access
to those user-provided properties.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>Note:</term>
<listitem>
<para>
The first time this function is called from the main fiber of a thread,
it may internally yield, permitting other fibers to run.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>See also:</term>
<listitem>
<para>
<link linkend="custom">Customization</link>
</para>
</listitem>
</varlistentry>
</variablelist>
</section>
</section>
<section id="fiber.scheduling">
<title><anchor id="scheduling"/><link linkend="fiber.scheduling">Scheduling</link></title>
<para>
The fibers in a thread are coordinated by a fiber manager. Fibers trade control
cooperatively, rather than preemptively: the currently-running fiber retains
control until it invokes some operation that passes control to the manager.
Each time a fiber suspends (or yields), the fiber manager consults a scheduler
to determine which fiber will run next.
</para>
<para>
<emphasis role="bold">Boost.Fiber</emphasis> provides the fiber manager, but
the scheduler is a customization point. (See <link linkend="custom">Customization</link>.)
</para>
<para>
Each thread has its own scheduler. Different threads in a process may use different
schedulers. By default, <emphasis role="bold">Boost.Fiber</emphasis> implicitly
instantiates <link linkend="class_round_robin"><code>round_robin</code></link> as the scheduler for each thread.
</para>
<para>
You are explicitly permitted to code your own <link linkend="class_algorithm"><code>algorithm</code></link> subclass.
For the most part, your <code><phrase role="identifier">algorithm</phrase></code>
subclass need not defend against cross-thread calls: the fiber manager intercepts
and defers such calls. Most <code><phrase role="identifier">algorithm</phrase></code>
methods are only ever directly called from the thread whose fibers it is managing
&mdash; with exceptions as documented below.
</para>
<para>
Your <code><phrase role="identifier">algorithm</phrase></code> subclass is
engaged on a particular thread by calling <link linkend="use_scheduling_algorithm"><code>use_scheduling_algorithm()</code></link>:
</para>
<programlisting><phrase role="keyword">void</phrase> <phrase role="identifier">thread_fn</phrase><phrase role="special">()</phrase> <phrase role="special">{</phrase>
<phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">fibers</phrase><phrase role="special">::</phrase><phrase role="identifier">use_scheduling_algorithm</phrase><phrase role="special">&lt;</phrase> <phrase role="identifier">my_fiber_scheduler</phrase> <phrase role="special">&gt;();</phrase>
<phrase role="special">...</phrase>
<phrase role="special">}</phrase>
</programlisting>
<para>
A scheduler class must implement interface <link linkend="class_algorithm"><code>algorithm</code></link>. <emphasis
role="bold">Boost.Fiber</emphasis> provides schedulers: <link linkend="class_round_robin"><code>round_robin</code></link>,
<link linkend="class_work_stealing"><code>work_stealing</code></link>, <link linkend="class_numa_work_stealing"><code>numa::work_stealing</code></link> and
<link linkend="class_shared_work"><code>shared_work</code></link>.
</para>
<programlisting><phrase role="keyword">void</phrase> <phrase role="identifier">thread</phrase><phrase role="special">(</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">uint32_t</phrase> <phrase role="identifier">thread_count</phrase><phrase role="special">)</phrase> <phrase role="special">{</phrase>
<phrase role="comment">// thread registers itself at work-stealing scheduler</phrase>
<phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">fibers</phrase><phrase role="special">::</phrase><phrase role="identifier">use_scheduling_algorithm</phrase><phrase role="special">&lt;</phrase> <phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">fibers</phrase><phrase role="special">::</phrase><phrase role="identifier">algo</phrase><phrase role="special">::</phrase><phrase role="identifier">work_stealing</phrase> <phrase role="special">&gt;(</phrase> <phrase role="identifier">thread_count</phrase><phrase role="special">);</phrase>
<phrase role="special">...</phrase>
<phrase role="special">}</phrase>
<phrase role="comment">// count of logical cpus</phrase>
<phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">uint32_t</phrase> <phrase role="identifier">thread_count</phrase> <phrase role="special">=</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">thread</phrase><phrase role="special">::</phrase><phrase role="identifier">hardware_concurrency</phrase><phrase role="special">();</phrase>
<phrase role="comment">// start worker-threads first</phrase>
<phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">vector</phrase><phrase role="special">&lt;</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">thread</phrase> <phrase role="special">&gt;</phrase> <phrase role="identifier">threads</phrase><phrase role="special">;</phrase>
<phrase role="keyword">for</phrase> <phrase role="special">(</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">uint32_t</phrase> <phrase role="identifier">i</phrase> <phrase role="special">=</phrase> <phrase role="number">1</phrase> <phrase role="comment">/* count start-thread */</phrase><phrase role="special">;</phrase> <phrase role="identifier">i</phrase> <phrase role="special">&lt;</phrase> <phrase role="identifier">thread_count</phrase><phrase role="special">;</phrase> <phrase role="special">++</phrase><phrase role="identifier">i</phrase><phrase role="special">)</phrase> <phrase role="special">{</phrase>
<phrase role="comment">// spawn thread</phrase>
<phrase role="identifier">threads</phrase><phrase role="special">.</phrase><phrase role="identifier">emplace_back</phrase><phrase role="special">(</phrase> <phrase role="identifier">thread</phrase><phrase role="special">,</phrase> <phrase role="identifier">thread_count</phrase><phrase role="special">);</phrase>
<phrase role="special">}</phrase>
<phrase role="comment">// start-thread registers itself at work-stealing scheduler</phrase>
<phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">fibers</phrase><phrase role="special">::</phrase><phrase role="identifier">use_scheduling_algorithm</phrase><phrase role="special">&lt;</phrase> <phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">fibers</phrase><phrase role="special">::</phrase><phrase role="identifier">algo</phrase><phrase role="special">::</phrase><phrase role="identifier">work_stealing</phrase> <phrase role="special">&gt;(</phrase> <phrase role="identifier">thread_count</phrase><phrase role="special">);</phrase>
<phrase role="special">...</phrase>
</programlisting>
<para>
The example spawns as many threads as <code><phrase role="identifier">std</phrase><phrase
role="special">::</phrase><phrase role="identifier">thread</phrase><phrase
role="special">::</phrase><phrase role="identifier">hardware_concurrency</phrase><phrase
role="special">()</phrase></code> returns. Each thread runs a <link linkend="class_work_stealing"><code>work_stealing</code></link> scheduler.
Each instance of this scheduler needs to know how many threads run the work-stealing
scheduler in the program. If the local queue of one thread runs out of ready
fibers, the thread tries to steal a ready fiber from another thread running
this scheduler.
</para>
<para>
<bridgehead renderas="sect4" id="class_algorithm_bridgehead">
<phrase id="class_algorithm"/>
<link linkend="class_algorithm">Class <code>algorithm</code></link>
</bridgehead>
</para>
<para>
<code><phrase role="identifier">algorithm</phrase></code> is the abstract base
class defining the interface that a fiber scheduler must implement.
</para>
<programlisting><phrase role="preprocessor">#include</phrase> <phrase role="special">&lt;</phrase><phrase role="identifier">boost</phrase><phrase role="special">/</phrase><phrase role="identifier">fiber</phrase><phrase role="special">/</phrase><phrase role="identifier">algo</phrase><phrase role="special">/</phrase><phrase role="identifier">algorithm</phrase><phrase role="special">.</phrase><phrase role="identifier">hpp</phrase><phrase role="special">&gt;</phrase>
<phrase role="keyword">namespace</phrase> <phrase role="identifier">boost</phrase> <phrase role="special">{</phrase>
<phrase role="keyword">namespace</phrase> <phrase role="identifier">fibers</phrase> <phrase role="special">{</phrase>
<phrase role="keyword">namespace</phrase> <phrase role="identifier">algo</phrase> <phrase role="special">{</phrase>
<phrase role="keyword">struct</phrase> <phrase role="identifier">algorithm</phrase> <phrase role="special">{</phrase>
<phrase role="keyword">virtual</phrase> <phrase role="special">~</phrase><phrase role="identifier">algorithm</phrase><phrase role="special">();</phrase>
<phrase role="keyword">virtual</phrase> <phrase role="keyword">void</phrase> <phrase role="identifier">awakened</phrase><phrase role="special">(</phrase> <phrase role="identifier">context</phrase> <phrase role="special">*)</phrase> <phrase role="keyword">noexcept</phrase> <phrase role="special">=</phrase> <phrase role="number">0</phrase><phrase role="special">;</phrase>
<phrase role="keyword">virtual</phrase> <phrase role="identifier">context</phrase> <phrase role="special">*</phrase> <phrase role="identifier">pick_next</phrase><phrase role="special">()</phrase> <phrase role="keyword">noexcept</phrase> <phrase role="special">=</phrase> <phrase role="number">0</phrase><phrase role="special">;</phrase>
<phrase role="keyword">virtual</phrase> <phrase role="keyword">bool</phrase> <phrase role="identifier">has_ready_fibers</phrase><phrase role="special">()</phrase> <phrase role="keyword">const</phrase> <phrase role="keyword">noexcept</phrase> <phrase role="special">=</phrase> <phrase role="number">0</phrase><phrase role="special">;</phrase>
<phrase role="keyword">virtual</phrase> <phrase role="keyword">void</phrase> <phrase role="identifier">suspend_until</phrase><phrase role="special">(</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">chrono</phrase><phrase role="special">::</phrase><phrase role="identifier">steady_clock</phrase><phrase role="special">::</phrase><phrase role="identifier">time_point</phrase> <phrase role="keyword">const</phrase><phrase role="special">&amp;)</phrase> <phrase role="keyword">noexcept</phrase> <phrase role="special">=</phrase> <phrase role="number">0</phrase><phrase role="special">;</phrase>
<phrase role="keyword">virtual</phrase> <phrase role="keyword">void</phrase> <phrase role="identifier">notify</phrase><phrase role="special">()</phrase> <phrase role="keyword">noexcept</phrase> <phrase role="special">=</phrase> <phrase role="number">0</phrase><phrase role="special">;</phrase>
<phrase role="special">};</phrase>
<phrase role="special">}}}</phrase>
</programlisting>
<para>
<bridgehead renderas="sect4" id="algorithm_awakened_bridgehead">
<phrase id="algorithm_awakened"/>
<link linkend="algorithm_awakened">Member function
<code>awakened</code>()</link>
</bridgehead>
</para>
<programlisting><phrase role="keyword">virtual</phrase> <phrase role="keyword">void</phrase> <phrase role="identifier">awakened</phrase><phrase role="special">(</phrase> <phrase role="identifier">context</phrase> <phrase role="special">*</phrase> <phrase role="identifier">f</phrase><phrase role="special">)</phrase> <phrase role="keyword">noexcept</phrase> <phrase role="special">=</phrase> <phrase role="number">0</phrase><phrase role="special">;</phrase>
</programlisting>
<variablelist>
<title></title>
<varlistentry>
<term>Effects:</term>
<listitem>
<para>
Informs the scheduler that fiber <code><phrase role="identifier">f</phrase></code>
is ready to run. Fiber <code><phrase role="identifier">f</phrase></code>
might be newly launched, or it might have been blocked but has just been
awakened, or it might have called <link linkend="this_fiber_yield"><code>this_fiber::yield()</code></link>.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>Note:</term>
<listitem>
<para>
This method advises the scheduler to add fiber <code><phrase role="identifier">f</phrase></code>
to its collection of fibers ready to run. A typical scheduler implementation
places <code><phrase role="identifier">f</phrase></code> into a queue.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>See also:</term>
<listitem>
<para>
<link linkend="class_round_robin"><code>round_robin</code></link>
</para>
</listitem>
</varlistentry>
</variablelist>
<para>
<bridgehead renderas="sect4" id="algorithm_pick_next_bridgehead">
<phrase id="algorithm_pick_next"/>
<link linkend="algorithm_pick_next">Member
function <code>pick_next</code>()</link>
</bridgehead>
</para>
<programlisting><phrase role="keyword">virtual</phrase> <phrase role="identifier">context</phrase> <phrase role="special">*</phrase> <phrase role="identifier">pick_next</phrase><phrase role="special">()</phrase> <phrase role="keyword">noexcept</phrase> <phrase role="special">=</phrase> <phrase role="number">0</phrase><phrase role="special">;</phrase>
</programlisting>
<variablelist>
<title></title>
<varlistentry>
<term>Returns:</term>
<listitem>
<para>
the fiber which is to be resumed next, or <code><phrase role="keyword">nullptr</phrase></code>
if there is no ready fiber.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>Note:</term>
<listitem>
<para>
This is where the scheduler actually specifies the fiber which is to
run next. A typical scheduler implementation chooses the head of the
ready queue.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>See also:</term>
<listitem>
<para>
<link linkend="class_round_robin"><code>round_robin</code></link>
</para>
</listitem>
</varlistentry>
</variablelist>
<para>
<bridgehead renderas="sect4" id="algorithm_has_ready_fibers_bridgehead">
<phrase id="algorithm_has_ready_fibers"/>
<link linkend="algorithm_has_ready_fibers">Member
function <code>has_ready_fibers</code>()</link>
</bridgehead>
</para>
<programlisting><phrase role="keyword">virtual</phrase> <phrase role="keyword">bool</phrase> <phrase role="identifier">has_ready_fibers</phrase><phrase role="special">()</phrase> <phrase role="keyword">const</phrase> <phrase role="keyword">noexcept</phrase> <phrase role="special">=</phrase> <phrase role="number">0</phrase><phrase role="special">;</phrase>
</programlisting>
<variablelist>
<title></title>
<varlistentry>
<term>Returns:</term>
<listitem>
<para>
<code><phrase role="keyword">true</phrase></code> if scheduler has fibers
ready to run.
</para>
</listitem>
</varlistentry>
</variablelist>
<para>
<bridgehead renderas="sect4" id="algorithm_suspend_until_bridgehead">
<phrase id="algorithm_suspend_until"/>
<link linkend="algorithm_suspend_until">Member
function <code>suspend_until</code>()</link>
</bridgehead>
</para>
<programlisting><phrase role="keyword">virtual</phrase> <phrase role="keyword">void</phrase> <phrase role="identifier">suspend_until</phrase><phrase role="special">(</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">chrono</phrase><phrase role="special">::</phrase><phrase role="identifier">steady_clock</phrase><phrase role="special">::</phrase><phrase role="identifier">time_point</phrase> <phrase role="keyword">const</phrase><phrase role="special">&amp;</phrase> <phrase role="identifier">abs_time</phrase><phrase role="special">)</phrase> <phrase role="keyword">noexcept</phrase> <phrase role="special">=</phrase> <phrase role="number">0</phrase><phrase role="special">;</phrase>
</programlisting>
<variablelist>
<title></title>
<varlistentry>
<term>Effects:</term>
<listitem>
<para>
Informs the scheduler that no fiber will be ready until time-point <code><phrase
role="identifier">abs_time</phrase></code>.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>Note:</term>
<listitem>
<para>
This method allows a custom scheduler to yield control to the containing
environment in whatever way makes sense. The fiber manager is stating
that <code><phrase role="identifier">suspend_until</phrase><phrase role="special">()</phrase></code>
need not return until <code><phrase role="identifier">abs_time</phrase></code>
&mdash; or <link linkend="algorithm_notify"><code>algorithm::notify()</code></link> is called &mdash; whichever comes first.
The interaction with <code><phrase role="identifier">notify</phrase><phrase
role="special">()</phrase></code> means that, for instance, calling
<ulink url="http://en.cppreference.com/w/cpp/thread/sleep_until"><code><phrase
role="identifier">std</phrase><phrase role="special">::</phrase><phrase
role="identifier">this_thread</phrase><phrase role="special">::</phrase><phrase
role="identifier">sleep_until</phrase><phrase role="special">(</phrase><phrase
role="identifier">abs_time</phrase><phrase role="special">)</phrase></code></ulink>
would be too simplistic. <link linkend="round_robin_suspend_until"><code>round_robin::suspend_until()</code></link> uses
a <ulink url="http://en.cppreference.com/w/cpp/thread/condition_variable"><code><phrase
role="identifier">std</phrase><phrase role="special">::</phrase><phrase
role="identifier">condition_variable</phrase></code></ulink> to coordinate
with <link linkend="round_robin_notify"><code>round_robin::notify()</code></link>.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>Note:</term>
<listitem>
<para>
Given that <code><phrase role="identifier">notify</phrase><phrase role="special">()</phrase></code>
might be called from another thread, your <code><phrase role="identifier">suspend_until</phrase><phrase
role="special">()</phrase></code> implementation &mdash; like the rest of your
<code><phrase role="identifier">algorithm</phrase></code> implementation
&mdash; must guard any data it shares with your <code><phrase role="identifier">notify</phrase><phrase
role="special">()</phrase></code> implementation.
</para>
</listitem>
</varlistentry>
</variablelist>
<para>
<bridgehead renderas="sect4" id="algorithm_notify_bridgehead">
<phrase id="algorithm_notify"/>
<link linkend="algorithm_notify">Member function
<code>notify</code>()</link>
</bridgehead>
</para>
<programlisting><phrase role="keyword">virtual</phrase> <phrase role="keyword">void</phrase> <phrase role="identifier">notify</phrase><phrase role="special">()</phrase> <phrase role="keyword">noexcept</phrase> <phrase role="special">=</phrase> <phrase role="number">0</phrase><phrase role="special">;</phrase>
</programlisting>
<variablelist>
<title></title>
<varlistentry>
<term>Effects:</term>
<listitem>
<para>
Requests the scheduler to return from a pending call to <link linkend="algorithm_suspend_until"><code>algorithm::suspend_until()</code></link>.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>Note:</term>
<listitem>
<para>
Alone among the <code><phrase role="identifier">algorithm</phrase></code>
methods, <code><phrase role="identifier">notify</phrase><phrase role="special">()</phrase></code>
may be called from another thread. Your <code><phrase role="identifier">notify</phrase><phrase
role="special">()</phrase></code> implementation must guard any data
it shares with the rest of your <code><phrase role="identifier">algorithm</phrase></code>
implementation.
</para>
</listitem>
</varlistentry>
</variablelist>
<para>
<bridgehead renderas="sect4" id="class_round_robin_bridgehead">
<phrase id="class_round_robin"/>
<link linkend="class_round_robin">Class <code>round_robin</code></link>
</bridgehead>
</para>
<para>
This class implements <link linkend="class_algorithm"><code>algorithm</code></link>, scheduling fibers in round-robin
fashion.
</para>
<programlisting><phrase role="preprocessor">#include</phrase> <phrase role="special">&lt;</phrase><phrase role="identifier">boost</phrase><phrase role="special">/</phrase><phrase role="identifier">fiber</phrase><phrase role="special">/</phrase><phrase role="identifier">algo</phrase><phrase role="special">/</phrase><phrase role="identifier">round_robin</phrase><phrase role="special">.</phrase><phrase role="identifier">hpp</phrase><phrase role="special">&gt;</phrase>
<phrase role="keyword">namespace</phrase> <phrase role="identifier">boost</phrase> <phrase role="special">{</phrase>
<phrase role="keyword">namespace</phrase> <phrase role="identifier">fibers</phrase> <phrase role="special">{</phrase>
<phrase role="keyword">namespace</phrase> <phrase role="identifier">algo</phrase> <phrase role="special">{</phrase>
<phrase role="keyword">class</phrase> <phrase role="identifier">round_robin</phrase> <phrase role="special">:</phrase> <phrase role="keyword">public</phrase> <phrase role="identifier">algorithm</phrase> <phrase role="special">{</phrase>
<phrase role="keyword">virtual</phrase> <phrase role="keyword">void</phrase> <phrase role="identifier">awakened</phrase><phrase role="special">(</phrase> <phrase role="identifier">context</phrase> <phrase role="special">*)</phrase> <phrase role="keyword">noexcept</phrase><phrase role="special">;</phrase>
<phrase role="keyword">virtual</phrase> <phrase role="identifier">context</phrase> <phrase role="special">*</phrase> <phrase role="identifier">pick_next</phrase><phrase role="special">()</phrase> <phrase role="keyword">noexcept</phrase><phrase role="special">;</phrase>
<phrase role="keyword">virtual</phrase> <phrase role="keyword">bool</phrase> <phrase role="identifier">has_ready_fibers</phrase><phrase role="special">()</phrase> <phrase role="keyword">const</phrase> <phrase role="keyword">noexcept</phrase><phrase role="special">;</phrase>
<phrase role="keyword">virtual</phrase> <phrase role="keyword">void</phrase> <phrase role="identifier">suspend_until</phrase><phrase role="special">(</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">chrono</phrase><phrase role="special">::</phrase><phrase role="identifier">steady_clock</phrase><phrase role="special">::</phrase><phrase role="identifier">time_point</phrase> <phrase role="keyword">const</phrase><phrase role="special">&amp;)</phrase> <phrase role="keyword">noexcept</phrase><phrase role="special">;</phrase>
<phrase role="keyword">virtual</phrase> <phrase role="keyword">void</phrase> <phrase role="identifier">notify</phrase><phrase role="special">()</phrase> <phrase role="keyword">noexcept</phrase><phrase role="special">;</phrase>
<phrase role="special">};</phrase>
<phrase role="special">}}}</phrase>
</programlisting>
<para>
<bridgehead renderas="sect4" id="round_robin_awakened_bridgehead">
<phrase id="round_robin_awakened"/>
<link linkend="round_robin_awakened">Member
function <code>awakened</code>()</link>
</bridgehead>
</para>
<programlisting><phrase role="keyword">virtual</phrase> <phrase role="keyword">void</phrase> <phrase role="identifier">awakened</phrase><phrase role="special">(</phrase> <phrase role="identifier">context</phrase> <phrase role="special">*</phrase> <phrase role="identifier">f</phrase><phrase role="special">)</phrase> <phrase role="keyword">noexcept</phrase><phrase role="special">;</phrase>
</programlisting>
<variablelist>
<title></title>
<varlistentry>
<term>Effects:</term>
<listitem>
<para>
Enqueues fiber <code><phrase role="identifier">f</phrase></code> onto
a ready queue.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>Throws:</term>
<listitem>
<para>
Nothing.
</para>
</listitem>
</varlistentry>
</variablelist>
<para>
<bridgehead renderas="sect4" id="round_robin_pick_next_bridgehead">
<phrase id="round_robin_pick_next"/>
<link linkend="round_robin_pick_next">Member
function <code>pick_next</code>()</link>
</bridgehead>
</para>
<programlisting><phrase role="keyword">virtual</phrase> <phrase role="identifier">context</phrase> <phrase role="special">*</phrase> <phrase role="identifier">pick_next</phrase><phrase role="special">()</phrase> <phrase role="keyword">noexcept</phrase><phrase role="special">;</phrase>
</programlisting>
<variablelist>
<title></title>
<varlistentry>
<term>Returns:</term>
<listitem>
<para>
the fiber at the head of the ready queue, or <code><phrase role="keyword">nullptr</phrase></code>
if the queue is empty.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>Throws:</term>
<listitem>
<para>
Nothing.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>Note:</term>
<listitem>
<para>
Placing ready fibers onto the tail of a queue, and returning them from
the head of that queue, shares the thread between ready fibers in round-robin
fashion.
</para>
</listitem>
</varlistentry>
</variablelist>
<para>
<bridgehead renderas="sect4" id="round_robin_has_ready_fibers_bridgehead">
<phrase id="round_robin_has_ready_fibers"/>
<link linkend="round_robin_has_ready_fibers">Member
function <code>has_ready_fibers</code>()</link>
</bridgehead>
</para>
<programlisting><phrase role="keyword">virtual</phrase> <phrase role="keyword">bool</phrase> <phrase role="identifier">has_ready_fibers</phrase><phrase role="special">()</phrase> <phrase role="keyword">const</phrase> <phrase role="keyword">noexcept</phrase><phrase role="special">;</phrase>
</programlisting>
<variablelist>
<title></title>
<varlistentry>
<term>Returns:</term>
<listitem>
<para>
<code><phrase role="keyword">true</phrase></code> if scheduler has fibers
ready to run.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>Throws:</term>
<listitem>
<para>
Nothing.
</para>
</listitem>
</varlistentry>
</variablelist>
<para>
<bridgehead renderas="sect4" id="round_robin_suspend_until_bridgehead">
<phrase id="round_robin_suspend_until"/>
<link linkend="round_robin_suspend_until">Member
function <code>suspend_until</code>()</link>
</bridgehead>
</para>
<programlisting><phrase role="keyword">virtual</phrase> <phrase role="keyword">void</phrase> <phrase role="identifier">suspend_until</phrase><phrase role="special">(</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">chrono</phrase><phrase role="special">::</phrase><phrase role="identifier">steady_clock</phrase><phrase role="special">::</phrase><phrase role="identifier">time_point</phrase> <phrase role="keyword">const</phrase><phrase role="special">&amp;</phrase> <phrase role="identifier">abs_time</phrase><phrase role="special">)</phrase> <phrase role="keyword">noexcept</phrase><phrase role="special">;</phrase>
</programlisting>
<variablelist>
<title></title>
<varlistentry>
<term>Effects:</term>
<listitem>
<para>
Informs <code><phrase role="identifier">round_robin</phrase></code> that
no ready fiber will be available until time-point <code><phrase role="identifier">abs_time</phrase></code>.
This implementation blocks in <ulink url="http://en.cppreference.com/w/cpp/thread/condition_variable/wait_until"><code><phrase
role="identifier">std</phrase><phrase role="special">::</phrase><phrase
role="identifier">condition_variable</phrase><phrase role="special">::</phrase><phrase
role="identifier">wait_until</phrase><phrase role="special">()</phrase></code></ulink>.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>Throws:</term>
<listitem>
<para>
Nothing.
</para>
</listitem>
</varlistentry>
</variablelist>
<para>
<bridgehead renderas="sect4" id="round_robin_notify_bridgehead">
<phrase id="round_robin_notify"/>
<link linkend="round_robin_notify">Member function
<code>notify</code>()</link>
</bridgehead>
</para>
<programlisting><phrase role="keyword">virtual</phrase> <phrase role="keyword">void</phrase> <phrase role="identifier">notify</phrase><phrase role="special">()</phrase> <phrase role="keyword">noexcept</phrase> <phrase role="special">=</phrase> <phrase role="number">0</phrase><phrase role="special">;</phrase>
</programlisting>
<variablelist>
<title></title>
<varlistentry>
<term>Effects:</term>
<listitem>
<para>
Wake up a pending call to <link linkend="round_robin_suspend_until"><code>round_robin::suspend_until()</code></link>,
some fibers might be ready. This implementation wakes <code><phrase role="identifier">suspend_until</phrase><phrase
role="special">()</phrase></code> via <ulink url="http://en.cppreference.com/w/cpp/thread/condition_variable/notify_all"><code><phrase
role="identifier">std</phrase><phrase role="special">::</phrase><phrase
role="identifier">condition_variable</phrase><phrase role="special">::</phrase><phrase
role="identifier">notify_all</phrase><phrase role="special">()</phrase></code></ulink>.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>Throws:</term>
<listitem>
<para>
Nothing.
</para>
</listitem>
</varlistentry>
</variablelist>
<para>
<bridgehead renderas="sect4" id="class_work_stealing_bridgehead">
<phrase id="class_work_stealing"/>
<link linkend="class_work_stealing">Class <code>work_stealing</code></link>
</bridgehead>
</para>
<para>
This class implements <link linkend="class_algorithm"><code>algorithm</code></link>; if the local ready-queue runs
out of ready fibers, ready fibers are stolen from other schedulers.<sbr/> The
victim scheduler (from which a ready fiber is stolen) is selected at random.
</para>
<note>
<para>
Worker-threads are stored in a static variable, dynamically adding/removing
worker threads is not supported.
</para>
</note>
<programlisting><phrase role="preprocessor">#include</phrase> <phrase role="special">&lt;</phrase><phrase role="identifier">boost</phrase><phrase role="special">/</phrase><phrase role="identifier">fiber</phrase><phrase role="special">/</phrase><phrase role="identifier">algo</phrase><phrase role="special">/</phrase><phrase role="identifier">work_stealing</phrase><phrase role="special">.</phrase><phrase role="identifier">hpp</phrase><phrase role="special">&gt;</phrase>
<phrase role="keyword">namespace</phrase> <phrase role="identifier">boost</phrase> <phrase role="special">{</phrase>
<phrase role="keyword">namespace</phrase> <phrase role="identifier">fibers</phrase> <phrase role="special">{</phrase>
<phrase role="keyword">namespace</phrase> <phrase role="identifier">algo</phrase> <phrase role="special">{</phrase>
<phrase role="keyword">class</phrase> <phrase role="identifier">work_stealing</phrase> <phrase role="special">:</phrase> <phrase role="keyword">public</phrase> <phrase role="identifier">algorithm</phrase> <phrase role="special">{</phrase>
<phrase role="keyword">public</phrase><phrase role="special">:</phrase>
<phrase role="identifier">work_stealing</phrase><phrase role="special">(</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">uint32_t</phrase> <phrase role="identifier">thread_count</phrase><phrase role="special">,</phrase> <phrase role="keyword">bool</phrase> <phrase role="identifier">suspend</phrase> <phrase role="special">=</phrase> <phrase role="keyword">false</phrase><phrase role="special">);</phrase>
<phrase role="identifier">work_stealing</phrase><phrase role="special">(</phrase> <phrase role="identifier">work_stealing</phrase> <phrase role="keyword">const</phrase><phrase role="special">&amp;)</phrase> <phrase role="special">=</phrase> <phrase role="keyword">delete</phrase><phrase role="special">;</phrase>
<phrase role="identifier">work_stealing</phrase><phrase role="special">(</phrase> <phrase role="identifier">work_stealing</phrase> <phrase role="special">&amp;&amp;)</phrase> <phrase role="special">=</phrase> <phrase role="keyword">delete</phrase><phrase role="special">;</phrase>
<phrase role="identifier">work_stealing</phrase> <phrase role="special">&amp;</phrase> <phrase role="keyword">operator</phrase><phrase role="special">=(</phrase> <phrase role="identifier">work_stealing</phrase> <phrase role="keyword">const</phrase><phrase role="special">&amp;)</phrase> <phrase role="special">=</phrase> <phrase role="keyword">delete</phrase><phrase role="special">;</phrase>
<phrase role="identifier">work_stealing</phrase> <phrase role="special">&amp;</phrase> <phrase role="keyword">operator</phrase><phrase role="special">=(</phrase> <phrase role="identifier">work_stealing</phrase> <phrase role="special">&amp;&amp;)</phrase> <phrase role="special">=</phrase> <phrase role="keyword">delete</phrase><phrase role="special">;</phrase>
<phrase role="keyword">virtual</phrase> <phrase role="keyword">void</phrase> <phrase role="identifier">awakened</phrase><phrase role="special">(</phrase> <phrase role="identifier">context</phrase> <phrase role="special">*)</phrase> <phrase role="keyword">noexcept</phrase><phrase role="special">;</phrase>
<phrase role="keyword">virtual</phrase> <phrase role="identifier">context</phrase> <phrase role="special">*</phrase> <phrase role="identifier">pick_next</phrase><phrase role="special">()</phrase> <phrase role="keyword">noexcept</phrase><phrase role="special">;</phrase>
<phrase role="keyword">virtual</phrase> <phrase role="keyword">bool</phrase> <phrase role="identifier">has_ready_fibers</phrase><phrase role="special">()</phrase> <phrase role="keyword">const</phrase> <phrase role="keyword">noexcept</phrase><phrase role="special">;</phrase>
<phrase role="keyword">virtual</phrase> <phrase role="keyword">void</phrase> <phrase role="identifier">suspend_until</phrase><phrase role="special">(</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">chrono</phrase><phrase role="special">::</phrase><phrase role="identifier">steady_clock</phrase><phrase role="special">::</phrase><phrase role="identifier">time_point</phrase> <phrase role="keyword">const</phrase><phrase role="special">&amp;)</phrase> <phrase role="keyword">noexcept</phrase><phrase role="special">;</phrase>
<phrase role="keyword">virtual</phrase> <phrase role="keyword">void</phrase> <phrase role="identifier">notify</phrase><phrase role="special">()</phrase> <phrase role="keyword">noexcept</phrase><phrase role="special">;</phrase>
<phrase role="special">};</phrase>
<phrase role="special">}}}</phrase>
</programlisting>
<bridgehead renderas="sect3" id="fiber.scheduling.h0">
<phrase id="fiber.scheduling.constructor"/><link linkend="fiber.scheduling.constructor">Constructor</link>
</bridgehead>
<programlisting><phrase role="identifier">work_stealing</phrase><phrase role="special">(</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">uint32_t</phrase> <phrase role="identifier">thread_count</phrase><phrase role="special">,</phrase> <phrase role="keyword">bool</phrase> <phrase role="identifier">suspend</phrase> <phrase role="special">=</phrase> <phrase role="keyword">false</phrase><phrase role="special">);</phrase>
</programlisting>
<variablelist>
<title></title>
<varlistentry>
<term>Effects:</term>
<listitem>
<para>
Constructs work-stealing scheduling algorithm. <code><phrase role="identifier">thread_count</phrase></code>
represents the number of threads running this algorithm.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>Throws:</term>
<listitem>
<para>
<code><phrase role="identifier">system_error</phrase></code>
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>Note:</term>
<listitem>
<para>
If <code><phrase role="identifier">suspend</phrase></code> is set to
<code><phrase role="keyword">true</phrase></code>, then the scheduler
suspends if no ready fiber could be stolen. The scheduler will by woken
up if a sleeping fiber times out or it was notified from remote (other
thread or fiber scheduler).
</para>
</listitem>
</varlistentry>
</variablelist>
<para>
<bridgehead renderas="sect4" id="work_stealing_awakened_bridgehead">
<phrase id="work_stealing_awakened"/>
<link linkend="work_stealing_awakened">Member
function <code>awakened</code>()</link>
</bridgehead>
</para>
<programlisting><phrase role="keyword">virtual</phrase> <phrase role="keyword">void</phrase> <phrase role="identifier">awakened</phrase><phrase role="special">(</phrase> <phrase role="identifier">context</phrase> <phrase role="special">*</phrase> <phrase role="identifier">f</phrase><phrase role="special">)</phrase> <phrase role="keyword">noexcept</phrase><phrase role="special">;</phrase>
</programlisting>
<variablelist>
<title></title>
<varlistentry>
<term>Effects:</term>
<listitem>
<para>
Enqueues fiber <code><phrase role="identifier">f</phrase></code> onto
the shared ready queue.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>Throws:</term>
<listitem>
<para>
Nothing.
</para>
</listitem>
</varlistentry>
</variablelist>
<para>
<bridgehead renderas="sect4" id="work_stealing_pick_next_bridgehead">
<phrase id="work_stealing_pick_next"/>
<link linkend="work_stealing_pick_next">Member
function <code>pick_next</code>()</link>
</bridgehead>
</para>
<programlisting><phrase role="keyword">virtual</phrase> <phrase role="identifier">context</phrase> <phrase role="special">*</phrase> <phrase role="identifier">pick_next</phrase><phrase role="special">()</phrase> <phrase role="keyword">noexcept</phrase><phrase role="special">;</phrase>
</programlisting>
<variablelist>
<title></title>
<varlistentry>
<term>Returns:</term>
<listitem>
<para>
the fiber at the head of the ready queue, or <code><phrase role="keyword">nullptr</phrase></code>
if the queue is empty.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>Throws:</term>
<listitem>
<para>
Nothing.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>Note:</term>
<listitem>
<para>
Placing ready fibers onto the tail of the sahred queue, and returning
them from the head of that queue, shares the thread between ready fibers
in round-robin fashion.
</para>
</listitem>
</varlistentry>
</variablelist>
<para>
<bridgehead renderas="sect4" id="work_stealing_has_ready_fibers_bridgehead">
<phrase id="work_stealing_has_ready_fibers"/>
<link linkend="work_stealing_has_ready_fibers">Member
function <code>has_ready_fibers</code>()</link>
</bridgehead>
</para>
<programlisting><phrase role="keyword">virtual</phrase> <phrase role="keyword">bool</phrase> <phrase role="identifier">has_ready_fibers</phrase><phrase role="special">()</phrase> <phrase role="keyword">const</phrase> <phrase role="keyword">noexcept</phrase><phrase role="special">;</phrase>
</programlisting>
<variablelist>
<title></title>
<varlistentry>
<term>Returns:</term>
<listitem>
<para>
<code><phrase role="keyword">true</phrase></code> if scheduler has fibers
ready to run.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>Throws:</term>
<listitem>
<para>
Nothing.
</para>
</listitem>
</varlistentry>
</variablelist>
<para>
<bridgehead renderas="sect4" id="work_stealing_suspend_until_bridgehead">
<phrase id="work_stealing_suspend_until"/>
<link linkend="work_stealing_suspend_until">Member
function <code>suspend_until</code>()</link>
</bridgehead>
</para>
<programlisting><phrase role="keyword">virtual</phrase> <phrase role="keyword">void</phrase> <phrase role="identifier">suspend_until</phrase><phrase role="special">(</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">chrono</phrase><phrase role="special">::</phrase><phrase role="identifier">steady_clock</phrase><phrase role="special">::</phrase><phrase role="identifier">time_point</phrase> <phrase role="keyword">const</phrase><phrase role="special">&amp;</phrase> <phrase role="identifier">abs_time</phrase><phrase role="special">)</phrase> <phrase role="keyword">noexcept</phrase><phrase role="special">;</phrase>
</programlisting>
<variablelist>
<title></title>
<varlistentry>
<term>Effects:</term>
<listitem>
<para>
Informs <code><phrase role="identifier">work_stealing</phrase></code>
that no ready fiber will be available until time-point <code><phrase
role="identifier">abs_time</phrase></code>. This implementation blocks
in <ulink url="http://en.cppreference.com/w/cpp/thread/condition_variable/wait_until"><code><phrase
role="identifier">std</phrase><phrase role="special">::</phrase><phrase
role="identifier">condition_variable</phrase><phrase role="special">::</phrase><phrase
role="identifier">wait_until</phrase><phrase role="special">()</phrase></code></ulink>.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>Throws:</term>
<listitem>
<para>
Nothing.
</para>
</listitem>
</varlistentry>
</variablelist>
<para>
<bridgehead renderas="sect4" id="work_stealing_notify_bridgehead">
<phrase id="work_stealing_notify"/>
<link linkend="work_stealing_notify">Member
function <code>notify</code>()</link>
</bridgehead>
</para>
<programlisting><phrase role="keyword">virtual</phrase> <phrase role="keyword">void</phrase> <phrase role="identifier">notify</phrase><phrase role="special">()</phrase> <phrase role="keyword">noexcept</phrase> <phrase role="special">=</phrase> <phrase role="number">0</phrase><phrase role="special">;</phrase>
</programlisting>
<variablelist>
<title></title>
<varlistentry>
<term>Effects:</term>
<listitem>
<para>
Wake up a pending call to <link linkend="work_stealing_suspend_until"><code>work_stealing::suspend_until()</code></link>,
some fibers might be ready. This implementation wakes <code><phrase role="identifier">suspend_until</phrase><phrase
role="special">()</phrase></code> via <ulink url="http://en.cppreference.com/w/cpp/thread/condition_variable/notify_all"><code><phrase
role="identifier">std</phrase><phrase role="special">::</phrase><phrase
role="identifier">condition_variable</phrase><phrase role="special">::</phrase><phrase
role="identifier">notify_all</phrase><phrase role="special">()</phrase></code></ulink>.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>Throws:</term>
<listitem>
<para>
Nothing.
</para>
</listitem>
</varlistentry>
</variablelist>
<para>
<bridgehead renderas="sect4" id="class_shared_work_bridgehead">
<phrase id="class_shared_work"/>
<link linkend="class_shared_work">Class <code>shared_work</code></link>
</bridgehead>
</para>
<note>
<para>
Because of the non-locality of data, <emphasis>shared_work</emphasis> is
less performant than <link linkend="class_work_stealing"><code>work_stealing</code></link>.
</para>
</note>
<para>
This class implements <link linkend="class_algorithm"><code>algorithm</code></link>, scheduling fibers in round-robin
fashion. Ready fibers are shared between all instances (running on different
threads) of shared_work, thus the work is distributed equally over all threads.
</para>
<note>
<para>
Worker-threads are stored in a static variable, dynamically adding/removing
worker threads is not supported.
</para>
</note>
<programlisting><phrase role="preprocessor">#include</phrase> <phrase role="special">&lt;</phrase><phrase role="identifier">boost</phrase><phrase role="special">/</phrase><phrase role="identifier">fiber</phrase><phrase role="special">/</phrase><phrase role="identifier">algo</phrase><phrase role="special">/</phrase><phrase role="identifier">shared_work</phrase><phrase role="special">.</phrase><phrase role="identifier">hpp</phrase><phrase role="special">&gt;</phrase>
<phrase role="keyword">namespace</phrase> <phrase role="identifier">boost</phrase> <phrase role="special">{</phrase>
<phrase role="keyword">namespace</phrase> <phrase role="identifier">fibers</phrase> <phrase role="special">{</phrase>
<phrase role="keyword">namespace</phrase> <phrase role="identifier">algo</phrase> <phrase role="special">{</phrase>
<phrase role="keyword">class</phrase> <phrase role="identifier">shared_work</phrase> <phrase role="special">:</phrase> <phrase role="keyword">public</phrase> <phrase role="identifier">algorithm</phrase> <phrase role="special">{</phrase>
<phrase role="keyword">virtual</phrase> <phrase role="keyword">void</phrase> <phrase role="identifier">awakened</phrase><phrase role="special">(</phrase> <phrase role="identifier">context</phrase> <phrase role="special">*)</phrase> <phrase role="keyword">noexcept</phrase><phrase role="special">;</phrase>
<phrase role="keyword">virtual</phrase> <phrase role="identifier">context</phrase> <phrase role="special">*</phrase> <phrase role="identifier">pick_next</phrase><phrase role="special">()</phrase> <phrase role="keyword">noexcept</phrase><phrase role="special">;</phrase>
<phrase role="keyword">virtual</phrase> <phrase role="keyword">bool</phrase> <phrase role="identifier">has_ready_fibers</phrase><phrase role="special">()</phrase> <phrase role="keyword">const</phrase> <phrase role="keyword">noexcept</phrase><phrase role="special">;</phrase>
<phrase role="keyword">virtual</phrase> <phrase role="keyword">void</phrase> <phrase role="identifier">suspend_until</phrase><phrase role="special">(</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">chrono</phrase><phrase role="special">::</phrase><phrase role="identifier">steady_clock</phrase><phrase role="special">::</phrase><phrase role="identifier">time_point</phrase> <phrase role="keyword">const</phrase><phrase role="special">&amp;)</phrase> <phrase role="keyword">noexcept</phrase><phrase role="special">;</phrase>
<phrase role="keyword">virtual</phrase> <phrase role="keyword">void</phrase> <phrase role="identifier">notify</phrase><phrase role="special">()</phrase> <phrase role="keyword">noexcept</phrase><phrase role="special">;</phrase>
<phrase role="special">};</phrase>
<phrase role="special">}}}</phrase>
</programlisting>
<para>
<bridgehead renderas="sect4" id="shared_work_awakened_bridgehead">
<phrase id="shared_work_awakened"/>
<link linkend="shared_work_awakened">Member
function <code>awakened</code>()</link>
</bridgehead>
</para>
<programlisting><phrase role="keyword">virtual</phrase> <phrase role="keyword">void</phrase> <phrase role="identifier">awakened</phrase><phrase role="special">(</phrase> <phrase role="identifier">context</phrase> <phrase role="special">*</phrase> <phrase role="identifier">f</phrase><phrase role="special">)</phrase> <phrase role="keyword">noexcept</phrase><phrase role="special">;</phrase>
</programlisting>
<variablelist>
<title></title>
<varlistentry>
<term>Effects:</term>
<listitem>
<para>
Enqueues fiber <code><phrase role="identifier">f</phrase></code> onto
the shared ready queue.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>Throws:</term>
<listitem>
<para>
Nothing.
</para>
</listitem>
</varlistentry>
</variablelist>
<para>
<bridgehead renderas="sect4" id="shared_work_pick_next_bridgehead">
<phrase id="shared_work_pick_next"/>
<link linkend="shared_work_pick_next">Member
function <code>pick_next</code>()</link>
</bridgehead>
</para>
<programlisting><phrase role="keyword">virtual</phrase> <phrase role="identifier">context</phrase> <phrase role="special">*</phrase> <phrase role="identifier">pick_next</phrase><phrase role="special">()</phrase> <phrase role="keyword">noexcept</phrase><phrase role="special">;</phrase>
</programlisting>
<variablelist>
<title></title>
<varlistentry>
<term>Returns:</term>
<listitem>
<para>
the fiber at the head of the ready queue, or <code><phrase role="keyword">nullptr</phrase></code>
if the queue is empty.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>Throws:</term>
<listitem>
<para>
Nothing.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>Note:</term>
<listitem>
<para>
Placing ready fibers onto the tail of the shared queue, and returning
them from the head of that queue, shares the thread between ready fibers
in round-robin fashion.
</para>
</listitem>
</varlistentry>
</variablelist>
<para>
<bridgehead renderas="sect4" id="shared_work_has_ready_fibers_bridgehead">
<phrase id="shared_work_has_ready_fibers"/>
<link linkend="shared_work_has_ready_fibers">Member
function <code>has_ready_fibers</code>()</link>
</bridgehead>
</para>
<programlisting><phrase role="keyword">virtual</phrase> <phrase role="keyword">bool</phrase> <phrase role="identifier">has_ready_fibers</phrase><phrase role="special">()</phrase> <phrase role="keyword">const</phrase> <phrase role="keyword">noexcept</phrase><phrase role="special">;</phrase>
</programlisting>
<variablelist>
<title></title>
<varlistentry>
<term>Returns:</term>
<listitem>
<para>
<code><phrase role="keyword">true</phrase></code> if scheduler has fibers
ready to run.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>Throws:</term>
<listitem>
<para>
Nothing.
</para>
</listitem>
</varlistentry>
</variablelist>
<para>
<bridgehead renderas="sect4" id="shared_work_suspend_until_bridgehead">
<phrase id="shared_work_suspend_until"/>
<link linkend="shared_work_suspend_until">Member
function <code>suspend_until</code>()</link>
</bridgehead>
</para>
<programlisting><phrase role="keyword">virtual</phrase> <phrase role="keyword">void</phrase> <phrase role="identifier">suspend_until</phrase><phrase role="special">(</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">chrono</phrase><phrase role="special">::</phrase><phrase role="identifier">steady_clock</phrase><phrase role="special">::</phrase><phrase role="identifier">time_point</phrase> <phrase role="keyword">const</phrase><phrase role="special">&amp;</phrase> <phrase role="identifier">abs_time</phrase><phrase role="special">)</phrase> <phrase role="keyword">noexcept</phrase><phrase role="special">;</phrase>
</programlisting>
<variablelist>
<title></title>
<varlistentry>
<term>Effects:</term>
<listitem>
<para>
Informs <code><phrase role="identifier">shared_work</phrase></code> that
no ready fiber will be available until time-point <code><phrase role="identifier">abs_time</phrase></code>.
This implementation blocks in <ulink url="http://en.cppreference.com/w/cpp/thread/condition_variable/wait_until"><code><phrase
role="identifier">std</phrase><phrase role="special">::</phrase><phrase
role="identifier">condition_variable</phrase><phrase role="special">::</phrase><phrase
role="identifier">wait_until</phrase><phrase role="special">()</phrase></code></ulink>.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>Throws:</term>
<listitem>
<para>
Nothing.
</para>
</listitem>
</varlistentry>
</variablelist>
<para>
<bridgehead renderas="sect4" id="shared_work_notify_bridgehead">
<phrase id="shared_work_notify"/>
<link linkend="shared_work_notify">Member function
<code>notify</code>()</link>
</bridgehead>
</para>
<programlisting><phrase role="keyword">virtual</phrase> <phrase role="keyword">void</phrase> <phrase role="identifier">notify</phrase><phrase role="special">()</phrase> <phrase role="keyword">noexcept</phrase> <phrase role="special">=</phrase> <phrase role="number">0</phrase><phrase role="special">;</phrase>
</programlisting>
<variablelist>
<title></title>
<varlistentry>
<term>Effects:</term>
<listitem>
<para>
Wake up a pending call to <link linkend="shared_work_suspend_until"><code>shared_work::suspend_until()</code></link>,
some fibers might be ready. This implementation wakes <code><phrase role="identifier">suspend_until</phrase><phrase
role="special">()</phrase></code> via <ulink url="http://en.cppreference.com/w/cpp/thread/condition_variable/notify_all"><code><phrase
role="identifier">std</phrase><phrase role="special">::</phrase><phrase
role="identifier">condition_variable</phrase><phrase role="special">::</phrase><phrase
role="identifier">notify_all</phrase><phrase role="special">()</phrase></code></ulink>.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>Throws:</term>
<listitem>
<para>
Nothing.
</para>
</listitem>
</varlistentry>
</variablelist>
<bridgehead renderas="sect3" id="fiber.scheduling.h1">
<phrase id="fiber.scheduling.custom_scheduler_fiber_properties"/><link linkend="fiber.scheduling.custom_scheduler_fiber_properties">Custom
Scheduler Fiber Properties</link>
</bridgehead>
<para>
A scheduler class directly derived from <link linkend="class_algorithm"><code>algorithm</code></link> can use any
information available from <link linkend="class_context"><code>context</code></link> to implement the <code><phrase
role="identifier">algorithm</phrase></code> interface. But a custom scheduler
might need to track additional properties for a fiber. For instance, a priority-based
scheduler would need to track a fiber&#8217;s priority.
</para>
<para>
<emphasis role="bold">Boost.Fiber</emphasis> provides a mechanism by which
your custom scheduler can associate custom properties with each fiber.
</para>
<para>
<bridgehead renderas="sect4" id="class_fiber_properties_bridgehead">
<phrase id="class_fiber_properties"/>
<link linkend="class_fiber_properties">Class
<code>fiber_properties</code></link>
</bridgehead>
</para>
<para>
A custom fiber properties class must be derived from <code><phrase role="identifier">fiber_properties</phrase></code>.
</para>
<programlisting><phrase role="preprocessor">#include</phrase> <phrase role="special">&lt;</phrase><phrase role="identifier">boost</phrase><phrase role="special">/</phrase><phrase role="identifier">fiber</phrase><phrase role="special">/</phrase><phrase role="identifier">properties</phrase><phrase role="special">.</phrase><phrase role="identifier">hpp</phrase><phrase role="special">&gt;</phrase>
<phrase role="keyword">namespace</phrase> <phrase role="identifier">boost</phrase> <phrase role="special">{</phrase>
<phrase role="keyword">namespace</phrase> <phrase role="identifier">fibers</phrase> <phrase role="special">{</phrase>
<phrase role="keyword">class</phrase> <phrase role="identifier">fiber_properties</phrase> <phrase role="special">{</phrase>
<phrase role="keyword">public</phrase><phrase role="special">:</phrase>
<phrase role="identifier">fiber_properties</phrase><phrase role="special">(</phrase> <phrase role="identifier">context</phrase> <phrase role="special">*)</phrase> <phrase role="keyword">noexcept</phrase><phrase role="special">;</phrase>
<phrase role="keyword">virtual</phrase> <phrase role="special">~</phrase><phrase role="identifier">fiber_properties</phrase><phrase role="special">();</phrase>
<phrase role="keyword">protected</phrase><phrase role="special">:</phrase>
<phrase role="keyword">void</phrase> <phrase role="identifier">notify</phrase><phrase role="special">()</phrase> <phrase role="keyword">noexcept</phrase><phrase role="special">;</phrase>
<phrase role="special">};</phrase>
<phrase role="special">}}</phrase>
</programlisting>
<bridgehead renderas="sect3" id="fiber.scheduling.h2">
<phrase id="fiber.scheduling.constructor0"/><link linkend="fiber.scheduling.constructor0">Constructor</link>
</bridgehead>
<programlisting><phrase role="identifier">fiber_properties</phrase><phrase role="special">(</phrase> <phrase role="identifier">context</phrase> <phrase role="special">*</phrase> <phrase role="identifier">f</phrase><phrase role="special">)</phrase> <phrase role="keyword">noexcept</phrase><phrase role="special">;</phrase>
</programlisting>
<variablelist>
<title></title>
<varlistentry>
<term>Effects:</term>
<listitem>
<para>
Constructs base-class component of custom subclass.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>Throws:</term>
<listitem>
<para>
Nothing.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>Note:</term>
<listitem>
<para>
Your subclass constructor must accept a <code><phrase role="identifier">context</phrase><phrase
role="special">*</phrase></code> and pass it to the base-class <code><phrase
role="identifier">fiber_properties</phrase></code> constructor.
</para>
</listitem>
</varlistentry>
</variablelist>
<para>
<bridgehead renderas="sect4" id="fiber_properties_notify_bridgehead">
<phrase id="fiber_properties_notify"/>
<link linkend="fiber_properties_notify">Member
function <code>notify</code>()</link>
</bridgehead>
</para>
<programlisting><phrase role="keyword">void</phrase> <phrase role="identifier">notify</phrase><phrase role="special">()</phrase> <phrase role="keyword">noexcept</phrase><phrase role="special">;</phrase>
</programlisting>
<variablelist>
<title></title>
<varlistentry>
<term>Effects:</term>
<listitem>
<para>
Pass control to the custom <link linkend="class_algorithm_with_properties"><code>algorithm_with_properties&lt;&gt;</code></link> subclass&#8217;s
<link linkend="algorithm_with_properties_property_change"><code>algorithm_with_properties::property_change()</code></link> method.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>Throws:</term>
<listitem>
<para>
Nothing.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>Note:</term>
<listitem>
<para>
A custom scheduler&#8217;s <link linkend="algorithm_with_properties_pick_next"><code>algorithm_with_properties::pick_next()</code></link> method
might dynamically select from the ready fibers, or <link linkend="algorithm_with_properties_awakened"><code>algorithm_with_properties::awakened()</code></link> might
instead insert each ready fiber into some form of ready queue for <code><phrase
role="identifier">pick_next</phrase><phrase role="special">()</phrase></code>.
In the latter case, if application code modifies a fiber property (e.g.
priority) that should affect that fiber&#8217;s relationship to other ready
fibers, the custom scheduler must be given the opportunity to reorder
its ready queue. The custom property subclass should implement an access
method to modify such a property; that access method should call <code><phrase
role="identifier">notify</phrase><phrase role="special">()</phrase></code>
once the new property value has been stored. This passes control to the
custom scheduler&#8217;s <code><phrase role="identifier">property_change</phrase><phrase
role="special">()</phrase></code> method, allowing the custom scheduler
to reorder its ready queue appropriately. Use at your discretion. Of
course, if you define a property which does not affect the behavior of
the <code><phrase role="identifier">pick_next</phrase><phrase role="special">()</phrase></code>
method, you need not call <code><phrase role="identifier">notify</phrase><phrase
role="special">()</phrase></code> when that property is modified.
</para>
</listitem>
</varlistentry>
</variablelist>
<para>
<bridgehead renderas="sect4" id="class_algorithm_with_properties_bridgehead">
<phrase id="class_algorithm_with_properties"/>
<link linkend="class_algorithm_with_properties">Template
<code>algorithm_with_properties&lt;&gt;</code></link>
</bridgehead>
</para>
<para>
A custom scheduler that depends on a custom properties class <code><phrase
role="identifier">PROPS</phrase></code> should be derived from <code><phrase
role="identifier">algorithm_with_properties</phrase><phrase role="special">&lt;</phrase><phrase
role="identifier">PROPS</phrase><phrase role="special">&gt;</phrase></code>.
<code><phrase role="identifier">PROPS</phrase></code> should be derived from
<link linkend="class_fiber_properties"><code>fiber_properties</code></link>.
</para>
<programlisting><phrase role="preprocessor">#include</phrase> <phrase role="special">&lt;</phrase><phrase role="identifier">boost</phrase><phrase role="special">/</phrase><phrase role="identifier">fiber</phrase><phrase role="special">/</phrase><phrase role="identifier">algorithm</phrase><phrase role="special">.</phrase><phrase role="identifier">hpp</phrase><phrase role="special">&gt;</phrase>
<phrase role="keyword">namespace</phrase> <phrase role="identifier">boost</phrase> <phrase role="special">{</phrase>
<phrase role="keyword">namespace</phrase> <phrase role="identifier">fibers</phrase> <phrase role="special">{</phrase>
<phrase role="keyword">namespace</phrase> <phrase role="identifier">algo</phrase> <phrase role="special">{</phrase>
<phrase role="keyword">template</phrase><phrase role="special">&lt;</phrase> <phrase role="keyword">typename</phrase> <phrase role="identifier">PROPS</phrase> <phrase role="special">&gt;</phrase>
<phrase role="keyword">struct</phrase> <phrase role="identifier">algorithm_with_properties</phrase> <phrase role="special">{</phrase>
<phrase role="keyword">virtual</phrase> <phrase role="keyword">void</phrase> <phrase role="identifier">awakened</phrase><phrase role="special">(</phrase> <phrase role="identifier">context</phrase> <phrase role="special">*,</phrase> <phrase role="identifier">PROPS</phrase> <phrase role="special">&amp;)</phrase> <phrase role="keyword">noexcept</phrase> <phrase role="special">=</phrase> <phrase role="number">0</phrase><phrase role="special">;</phrase>
<phrase role="keyword">virtual</phrase> <phrase role="identifier">context</phrase> <phrase role="special">*</phrase> <phrase role="identifier">pick_next</phrase><phrase role="special">()</phrase> <phrase role="keyword">noexcept</phrase><phrase role="special">;</phrase>
<phrase role="keyword">virtual</phrase> <phrase role="keyword">bool</phrase> <phrase role="identifier">has_ready_fibers</phrase><phrase role="special">()</phrase> <phrase role="keyword">const</phrase> <phrase role="keyword">noexcept</phrase><phrase role="special">;</phrase>
<phrase role="keyword">virtual</phrase> <phrase role="keyword">void</phrase> <phrase role="identifier">suspend_until</phrase><phrase role="special">(</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">chrono</phrase><phrase role="special">::</phrase><phrase role="identifier">steady_clock</phrase><phrase role="special">::</phrase><phrase role="identifier">time_point</phrase> <phrase role="keyword">const</phrase><phrase role="special">&amp;)</phrase> <phrase role="keyword">noexcept</phrase> <phrase role="special">=</phrase> <phrase role="number">0</phrase><phrase role="special">;</phrase>
<phrase role="keyword">virtual</phrase> <phrase role="keyword">void</phrase> <phrase role="identifier">notify</phrase><phrase role="special">()</phrase> <phrase role="keyword">noexcept</phrase> <phrase role="special">=</phrase> <phrase role="number">0</phrase><phrase role="special">;</phrase>
<phrase role="identifier">PROPS</phrase> <phrase role="special">&amp;</phrase> <phrase role="identifier">properties</phrase><phrase role="special">(</phrase> <phrase role="identifier">context</phrase> <phrase role="special">*)</phrase> <phrase role="keyword">noexcept</phrase><phrase role="special">;</phrase>
<phrase role="keyword">virtual</phrase> <phrase role="keyword">void</phrase> <phrase role="identifier">property_change</phrase><phrase role="special">(</phrase> <phrase role="identifier">context</phrase> <phrase role="special">*,</phrase> <phrase role="identifier">PROPS</phrase> <phrase role="special">&amp;)</phrase> <phrase role="keyword">noexcept</phrase><phrase role="special">;</phrase>
<phrase role="keyword">virtual</phrase> <phrase role="identifier">fiber_properties</phrase> <phrase role="special">*</phrase> <phrase role="identifier">new_properties</phrase><phrase role="special">(</phrase> <phrase role="identifier">context</phrase> <phrase role="special">*);</phrase>
<phrase role="special">};</phrase>
<phrase role="special">}}}</phrase>
</programlisting>
<para>
<bridgehead renderas="sect4" id="algorithm_with_properties_awakened_bridgehead">
<phrase id="algorithm_with_properties_awakened"/>
<link linkend="algorithm_with_properties_awakened">Member
function <code>awakened</code>()</link>
</bridgehead>
</para>
<programlisting><phrase role="keyword">virtual</phrase> <phrase role="keyword">void</phrase> <phrase role="identifier">awakened</phrase><phrase role="special">(</phrase> <phrase role="identifier">context</phrase> <phrase role="special">*</phrase> <phrase role="identifier">f</phrase><phrase role="special">,</phrase> <phrase role="identifier">PROPS</phrase> <phrase role="special">&amp;</phrase> <phrase role="identifier">properties</phrase><phrase role="special">)</phrase> <phrase role="keyword">noexcept</phrase><phrase role="special">;</phrase>
</programlisting>
<variablelist>
<title></title>
<varlistentry>
<term>Effects:</term>
<listitem>
<para>
Informs the scheduler that fiber <code><phrase role="identifier">f</phrase></code>
is ready to run, like <link linkend="algorithm_awakened"><code>algorithm::awakened()</code></link>. Passes
the fiber&#8217;s associated <code><phrase role="identifier">PROPS</phrase></code>
instance.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>Throws:</term>
<listitem>
<para>
Nothing.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>Note:</term>
<listitem>
<para>
An <code><phrase role="identifier">algorithm_with_properties</phrase><phrase
role="special">&lt;&gt;</phrase></code> subclass must override this method
instead of <code><phrase role="identifier">algorithm</phrase><phrase
role="special">::</phrase><phrase role="identifier">awakened</phrase><phrase
role="special">()</phrase></code>.
</para>
</listitem>
</varlistentry>
</variablelist>
<para>
<bridgehead renderas="sect4" id="algorithm_with_properties_pick_next_bridgehead">
<phrase id="algorithm_with_properties_pick_next"/>
<link linkend="algorithm_with_properties_pick_next">Member
function <code>pick_next</code>()</link>
</bridgehead>
</para>
<programlisting><phrase role="keyword">virtual</phrase> <phrase role="identifier">context</phrase> <phrase role="special">*</phrase> <phrase role="identifier">pick_next</phrase><phrase role="special">()</phrase> <phrase role="keyword">noexcept</phrase><phrase role="special">;</phrase>
</programlisting>
<variablelist>
<title></title>
<varlistentry>
<term>Returns:</term>
<listitem>
<para>
the fiber which is to be resumed next, or <code><phrase role="keyword">nullptr</phrase></code>
if there is no ready fiber.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>Throws:</term>
<listitem>
<para>
Nothing.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>Note:</term>
<listitem>
<para>
same as <link linkend="algorithm_pick_next"><code>algorithm::pick_next()</code></link>
</para>
</listitem>
</varlistentry>
</variablelist>
<para>
<bridgehead renderas="sect4" id="algorithm_with_properties_has_ready_fibers_bridgehead">
<phrase id="algorithm_with_properties_has_ready_fibers"/>
<link linkend="algorithm_with_properties_has_ready_fibers">Member
function <code>has_ready_fibers</code>()</link>
</bridgehead>
</para>
<programlisting><phrase role="keyword">virtual</phrase> <phrase role="keyword">bool</phrase> <phrase role="identifier">has_ready_fibers</phrase><phrase role="special">()</phrase> <phrase role="keyword">const</phrase> <phrase role="keyword">noexcept</phrase><phrase role="special">;</phrase>
</programlisting>
<variablelist>
<title></title>
<varlistentry>
<term>Returns:</term>
<listitem>
<para>
<code><phrase role="keyword">true</phrase></code> if scheduler has fibers
ready to run.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>Throws:</term>
<listitem>
<para>
Nothing.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>Note:</term>
<listitem>
<para>
same as <link linkend="algorithm_has_ready_fibers"><code>algorithm::has_ready_fibers()</code></link>
</para>
</listitem>
</varlistentry>
</variablelist>
<para>
<bridgehead renderas="sect4" id="algorithm_with_properties_suspend_until_bridgehead">
<phrase id="algorithm_with_properties_suspend_until"/>
<link linkend="algorithm_with_properties_suspend_until">Member
function <code>suspend_until</code>()</link>
</bridgehead>
</para>
<programlisting><phrase role="keyword">virtual</phrase> <phrase role="keyword">void</phrase> <phrase role="identifier">suspend_until</phrase><phrase role="special">(</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">chrono</phrase><phrase role="special">::</phrase><phrase role="identifier">steady_clock</phrase><phrase role="special">::</phrase><phrase role="identifier">time_point</phrase> <phrase role="keyword">const</phrase><phrase role="special">&amp;</phrase> <phrase role="identifier">abs_time</phrase><phrase role="special">)</phrase> <phrase role="keyword">noexcept</phrase> <phrase role="special">=</phrase> <phrase role="number">0</phrase><phrase role="special">;</phrase>
</programlisting>
<variablelist>
<title></title>
<varlistentry>
<term>Effects:</term>
<listitem>
<para>
Informs the scheduler that no fiber will be ready until time-point <code><phrase
role="identifier">abs_time</phrase></code>.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>Note:</term>
<listitem>
<para>
same as <link linkend="algorithm_suspend_until"><code>algorithm::suspend_until()</code></link>
</para>
</listitem>
</varlistentry>
</variablelist>
<para>
<bridgehead renderas="sect4" id="algorithm_with_properties_notify_bridgehead">
<phrase id="algorithm_with_properties_notify"/>
<link linkend="algorithm_with_properties_notify">Member
function <code>notify</code>()</link>
</bridgehead>
</para>
<programlisting><phrase role="keyword">virtual</phrase> <phrase role="keyword">void</phrase> <phrase role="identifier">notify</phrase><phrase role="special">()</phrase> <phrase role="keyword">noexcept</phrase> <phrase role="special">=</phrase> <phrase role="number">0</phrase><phrase role="special">;</phrase>
</programlisting>
<variablelist>
<title></title>
<varlistentry>
<term>Effects:</term>
<listitem>
<para>
Requests the scheduler to return from a pending call to <link linkend="algorithm_with_properties_suspend_until"><code>algorithm_with_properties::suspend_until()</code></link>.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>Note:</term>
<listitem>
<para>
same as <link linkend="algorithm_notify"><code>algorithm::notify()</code></link>
</para>
</listitem>
</varlistentry>
</variablelist>
<para>
<bridgehead renderas="sect4" id="algorithm_with_properties_properties_bridgehead">
<phrase id="algorithm_with_properties_properties"/>
<link linkend="algorithm_with_properties_properties">Member
function <code>properties</code>()</link>
</bridgehead>
</para>
<programlisting><phrase role="identifier">PROPS</phrase><phrase role="special">&amp;</phrase> <phrase role="identifier">properties</phrase><phrase role="special">(</phrase> <phrase role="identifier">context</phrase> <phrase role="special">*</phrase> <phrase role="identifier">f</phrase><phrase role="special">)</phrase> <phrase role="keyword">noexcept</phrase><phrase role="special">;</phrase>
</programlisting>
<variablelist>
<title></title>
<varlistentry>
<term>Returns:</term>
<listitem>
<para>
the <code><phrase role="identifier">PROPS</phrase></code> instance associated
with fiber <code><phrase role="identifier">f</phrase></code>.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>Throws:</term>
<listitem>
<para>
Nothing.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>Note:</term>
<listitem>
<para>
The fiber&#8217;s associated <code><phrase role="identifier">PROPS</phrase></code>
instance is already passed to <link linkend="algorithm_with_properties_awakened"><code>algorithm_with_properties::awakened()</code></link> and
<link linkend="algorithm_with_properties_property_change"><code>algorithm_with_properties::property_change()</code></link>.
However, every <link linkend="class_algorithm"><code>algorithm</code></link> subclass is expected to track
a collection of ready <link linkend="class_context"><code>context</code></link> instances. This method allows
your custom scheduler to retrieve the <link linkend="class_fiber_properties"><code>fiber_properties</code></link> subclass
instance for any <code><phrase role="identifier">context</phrase></code>
in its collection.
</para>
</listitem>
</varlistentry>
</variablelist>
<para>
<bridgehead renderas="sect4" id="algorithm_with_properties_property_change_bridgehead">
<phrase id="algorithm_with_properties_property_change"/>
<link linkend="algorithm_with_properties_property_change">Member
function <code>property_change</code>()</link>
</bridgehead>
</para>
<programlisting><phrase role="keyword">virtual</phrase> <phrase role="keyword">void</phrase> <phrase role="identifier">property_change</phrase><phrase role="special">(</phrase> <phrase role="identifier">context</phrase> <phrase role="special">*</phrase> <phrase role="identifier">f</phrase><phrase role="special">,</phrase> <phrase role="identifier">PROPS</phrase> <phrase role="special">&amp;</phrase> <phrase role="identifier">properties</phrase><phrase role="special">)</phrase> <phrase role="keyword">noexcept</phrase><phrase role="special">;</phrase>
</programlisting>
<variablelist>
<title></title>
<varlistentry>
<term>Effects:</term>
<listitem>
<para>
Notify the custom scheduler of a possibly-relevant change to a property
belonging to fiber <code><phrase role="identifier">f</phrase></code>.
<code><phrase role="identifier">properties</phrase></code> contains the
new values of all relevant properties.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>Throws:</term>
<listitem>
<para>
Nothing.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>Note:</term>
<listitem>
<para>
This method is only called when a custom <link linkend="class_fiber_properties"><code>fiber_properties</code></link> subclass
explicitly calls <link linkend="fiber_properties_notify"><code>fiber_properties::notify()</code></link>.
</para>
</listitem>
</varlistentry>
</variablelist>
<para>
<bridgehead renderas="sect4" id="algorithm_with_properties_new_properties_bridgehead">
<phrase id="algorithm_with_properties_new_properties"/>
<link linkend="algorithm_with_properties_new_properties">Member
function <code>new_properties</code>()</link>
</bridgehead>
</para>
<programlisting><phrase role="keyword">virtual</phrase> <phrase role="identifier">fiber_properties</phrase> <phrase role="special">*</phrase> <phrase role="identifier">new_properties</phrase><phrase role="special">(</phrase> <phrase role="identifier">context</phrase> <phrase role="special">*</phrase> <phrase role="identifier">f</phrase><phrase role="special">);</phrase>
</programlisting>
<variablelist>
<title></title>
<varlistentry>
<term>Returns:</term>
<listitem>
<para>
A new instance of <link linkend="class_fiber_properties"><code>fiber_properties</code></link> subclass <code><phrase
role="identifier">PROPS</phrase></code>.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>Note:</term>
<listitem>
<para>
By default, <code><phrase role="identifier">algorithm_with_properties</phrase><phrase
role="special">&lt;&gt;::</phrase><phrase role="identifier">new_properties</phrase><phrase
role="special">()</phrase></code> simply returns <code><phrase role="keyword">new</phrase>
<phrase role="identifier">PROPS</phrase><phrase role="special">(</phrase><phrase
role="identifier">f</phrase><phrase role="special">)</phrase></code>,
placing the <code><phrase role="identifier">PROPS</phrase></code> instance
on the heap. Override this method to allocate <code><phrase role="identifier">PROPS</phrase></code>
some other way. The returned <code><phrase role="identifier">fiber_properties</phrase></code>
pointer must point to the <code><phrase role="identifier">PROPS</phrase></code>
instance to be associated with fiber <code><phrase role="identifier">f</phrase></code>.
</para>
</listitem>
</varlistentry>
</variablelist>
<para>
<anchor id="context"/><bridgehead renderas="sect4" id="class_context_bridgehead">
<phrase id="class_context"/>
<link linkend="class_context">Class
<code>context</code></link>
</bridgehead>
</para>
<para>
While you are free to treat <code><phrase role="identifier">context</phrase><phrase
role="special">*</phrase></code> as an opaque token, certain <code><phrase
role="identifier">context</phrase></code> members may be useful to a custom
scheduler implementation.
</para>
<para>
<anchor id="ready_queue_t"/>Of particular note is the fact that <code><phrase
role="identifier">context</phrase></code> contains a hook to participate in
a <ulink url="http://www.boost.org/doc/libs/release/doc/html/intrusive/list.html"><code><phrase
role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">intrusive</phrase><phrase
role="special">::</phrase><phrase role="identifier">list</phrase></code></ulink>
<literal>typedef</literal>&#8217;ed as <code><phrase role="identifier">boost</phrase><phrase
role="special">::</phrase><phrase role="identifier">fibers</phrase><phrase
role="special">::</phrase><phrase role="identifier">scheduler</phrase><phrase
role="special">::</phrase><phrase role="identifier">ready_queue_t</phrase></code>.
This hook is reserved for use by <link linkend="class_algorithm"><code>algorithm</code></link> implementations. (For
instance, <link linkend="class_round_robin"><code>round_robin</code></link> contains a <code><phrase role="identifier">ready_queue_t</phrase></code>
instance to manage its ready fibers.) See <link linkend="context_ready_is_linked"><code>context::ready_is_linked()</code></link>,
<link linkend="context_ready_link"><code>context::ready_link()</code></link>, <link linkend="context_ready_unlink"><code>context::ready_unlink()</code></link>.
</para>
<para>
Your <code><phrase role="identifier">algorithm</phrase></code> implementation
may use any container you desire to manage passed <code><phrase role="identifier">context</phrase></code>
instances. <code><phrase role="identifier">ready_queue_t</phrase></code> avoids
some of the overhead of typical STL containers.
</para>
<programlisting><phrase role="preprocessor">#include</phrase> <phrase role="special">&lt;</phrase><phrase role="identifier">boost</phrase><phrase role="special">/</phrase><phrase role="identifier">fiber</phrase><phrase role="special">/</phrase><phrase role="identifier">context</phrase><phrase role="special">.</phrase><phrase role="identifier">hpp</phrase><phrase role="special">&gt;</phrase>
<phrase role="keyword">namespace</phrase> <phrase role="identifier">boost</phrase> <phrase role="special">{</phrase>
<phrase role="keyword">namespace</phrase> <phrase role="identifier">fibers</phrase> <phrase role="special">{</phrase>
<phrase role="keyword">enum</phrase> <phrase role="keyword">class</phrase> <phrase role="identifier">type</phrase> <phrase role="special">{</phrase>
<phrase role="identifier">none</phrase> <phrase role="special">=</phrase> <emphasis>unspecified</emphasis><phrase role="special">,</phrase>
<phrase role="identifier">main_context</phrase> <phrase role="special">=</phrase> <emphasis>unspecified</emphasis><phrase role="special">,</phrase> <phrase role="comment">// fiber associated with thread's stack</phrase>
<phrase role="identifier">dispatcher_context</phrase> <phrase role="special">=</phrase> <emphasis>unspecified</emphasis><phrase role="special">,</phrase> <phrase role="comment">// special fiber for maintenance operations</phrase>
<phrase role="identifier">worker_context</phrase> <phrase role="special">=</phrase> <emphasis>unspecified</emphasis><phrase role="special">,</phrase> <phrase role="comment">// fiber not special to the library</phrase>
<phrase role="identifier">pinned_context</phrase> <phrase role="special">=</phrase> <emphasis>unspecified</emphasis> <phrase role="comment">// fiber must not be migrated to another thread</phrase>
<phrase role="special">};</phrase>
<phrase role="keyword">class</phrase> <phrase role="identifier">context</phrase> <phrase role="special">{</phrase>
<phrase role="keyword">public</phrase><phrase role="special">:</phrase>
<phrase role="keyword">class</phrase> <phrase role="identifier">id</phrase><phrase role="special">;</phrase>
<phrase role="keyword">static</phrase> <phrase role="identifier">context</phrase> <phrase role="special">*</phrase> <phrase role="identifier">active</phrase><phrase role="special">()</phrase> <phrase role="keyword">noexcept</phrase><phrase role="special">;</phrase>
<phrase role="identifier">context</phrase><phrase role="special">(</phrase> <phrase role="identifier">context</phrase> <phrase role="keyword">const</phrase><phrase role="special">&amp;)</phrase> <phrase role="special">=</phrase> <phrase role="keyword">delete</phrase><phrase role="special">;</phrase>
<phrase role="identifier">context</phrase> <phrase role="special">&amp;</phrase> <phrase role="keyword">operator</phrase><phrase role="special">=(</phrase> <phrase role="identifier">context</phrase> <phrase role="keyword">const</phrase><phrase role="special">&amp;)</phrase> <phrase role="special">=</phrase> <phrase role="keyword">delete</phrase><phrase role="special">;</phrase>
<phrase role="identifier">id</phrase> <phrase role="identifier">get_id</phrase><phrase role="special">()</phrase> <phrase role="keyword">const</phrase> <phrase role="keyword">noexcept</phrase><phrase role="special">;</phrase>
<phrase role="keyword">void</phrase> <phrase role="identifier">detach</phrase><phrase role="special">()</phrase> <phrase role="keyword">noexcept</phrase><phrase role="special">;</phrase>
<phrase role="keyword">void</phrase> <phrase role="identifier">attach</phrase><phrase role="special">(</phrase> <phrase role="identifier">context</phrase> <phrase role="special">*)</phrase> <phrase role="keyword">noexcept</phrase><phrase role="special">;</phrase>
<phrase role="keyword">bool</phrase> <phrase role="identifier">is_context</phrase><phrase role="special">(</phrase> <phrase role="identifier">type</phrase><phrase role="special">)</phrase> <phrase role="keyword">const</phrase> <phrase role="keyword">noexcept</phrase><phrase role="special">;</phrase>
<phrase role="keyword">bool</phrase> <phrase role="identifier">is_terminated</phrase><phrase role="special">()</phrase> <phrase role="keyword">const</phrase> <phrase role="keyword">noexcept</phrase><phrase role="special">;</phrase>
<phrase role="keyword">bool</phrase> <phrase role="identifier">ready_is_linked</phrase><phrase role="special">()</phrase> <phrase role="keyword">const</phrase> <phrase role="keyword">noexcept</phrase><phrase role="special">;</phrase>
<phrase role="keyword">bool</phrase> <phrase role="identifier">remote_ready_is_linked</phrase><phrase role="special">()</phrase> <phrase role="keyword">const</phrase> <phrase role="keyword">noexcept</phrase><phrase role="special">;</phrase>
<phrase role="keyword">bool</phrase> <phrase role="identifier">wait_is_linked</phrase><phrase role="special">()</phrase> <phrase role="keyword">const</phrase> <phrase role="keyword">noexcept</phrase><phrase role="special">;</phrase>
<phrase role="keyword">template</phrase><phrase role="special">&lt;</phrase> <phrase role="keyword">typename</phrase> <phrase role="identifier">List</phrase> <phrase role="special">&gt;</phrase>
<phrase role="keyword">void</phrase> <phrase role="identifier">ready_link</phrase><phrase role="special">(</phrase> <phrase role="identifier">List</phrase> <phrase role="special">&amp;)</phrase> <phrase role="keyword">noexcept</phrase><phrase role="special">;</phrase>
<phrase role="keyword">template</phrase><phrase role="special">&lt;</phrase> <phrase role="keyword">typename</phrase> <phrase role="identifier">List</phrase> <phrase role="special">&gt;</phrase>
<phrase role="keyword">void</phrase> <phrase role="identifier">remote_ready_link</phrase><phrase role="special">(</phrase> <phrase role="identifier">List</phrase> <phrase role="special">&amp;)</phrase> <phrase role="keyword">noexcept</phrase><phrase role="special">;</phrase>
<phrase role="keyword">template</phrase><phrase role="special">&lt;</phrase> <phrase role="keyword">typename</phrase> <phrase role="identifier">List</phrase> <phrase role="special">&gt;</phrase>
<phrase role="keyword">void</phrase> <phrase role="identifier">wait_link</phrase><phrase role="special">(</phrase> <phrase role="identifier">List</phrase> <phrase role="special">&amp;)</phrase> <phrase role="keyword">noexcept</phrase><phrase role="special">;</phrase>
<phrase role="keyword">void</phrase> <phrase role="identifier">ready_unlink</phrase><phrase role="special">()</phrase> <phrase role="keyword">noexcept</phrase><phrase role="special">;</phrase>
<phrase role="keyword">void</phrase> <phrase role="identifier">remote_ready_unlink</phrase><phrase role="special">()</phrase> <phrase role="keyword">noexcept</phrase><phrase role="special">;</phrase>
<phrase role="keyword">void</phrase> <phrase role="identifier">wait_unlink</phrase><phrase role="special">()</phrase> <phrase role="keyword">noexcept</phrase><phrase role="special">;</phrase>
<phrase role="keyword">void</phrase> <phrase role="identifier">suspend</phrase><phrase role="special">()</phrase> <phrase role="keyword">noexcept</phrase><phrase role="special">;</phrase>
<phrase role="keyword">void</phrase> <phrase role="identifier">schedule</phrase><phrase role="special">(</phrase> <phrase role="identifier">context</phrase> <phrase role="special">*)</phrase> <phrase role="keyword">noexcept</phrase><phrase role="special">;</phrase>
<phrase role="special">};</phrase>
<phrase role="keyword">bool</phrase> <phrase role="keyword">operator</phrase><phrase role="special">&lt;(</phrase> <phrase role="identifier">context</phrase> <phrase role="keyword">const</phrase><phrase role="special">&amp;</phrase> <phrase role="identifier">l</phrase><phrase role="special">,</phrase> <phrase role="identifier">context</phrase> <phrase role="keyword">const</phrase><phrase role="special">&amp;</phrase> <phrase role="identifier">r</phrase><phrase role="special">)</phrase> <phrase role="keyword">noexcept</phrase><phrase role="special">;</phrase>
<phrase role="special">}}</phrase>
</programlisting>
<para>
<bridgehead renderas="sect4" id="context_active_bridgehead">
<phrase id="context_active"/>
<link linkend="context_active">Static member function
<code>active</code>()</link>
</bridgehead>
</para>
<programlisting><phrase role="keyword">static</phrase> <phrase role="identifier">context</phrase> <phrase role="special">*</phrase> <phrase role="identifier">active</phrase><phrase role="special">()</phrase> <phrase role="keyword">noexcept</phrase><phrase role="special">;</phrase>
</programlisting>
<variablelist>
<title></title>
<varlistentry>
<term>Returns:</term>
<listitem>
<para>
Pointer to instance of current fiber.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>Throws:</term>
<listitem>
<para>
Nothing
</para>
</listitem>
</varlistentry>
</variablelist>
<para>
<bridgehead renderas="sect4" id="context_get_id_bridgehead">
<phrase id="context_get_id"/>
<link linkend="context_get_id">Member function <code>get_id</code>()</link>
</bridgehead>
</para>
<programlisting><phrase role="identifier">context</phrase><phrase role="special">::</phrase><phrase role="identifier">id</phrase> <phrase role="identifier">get_id</phrase><phrase role="special">()</phrase> <phrase role="keyword">const</phrase> <phrase role="keyword">noexcept</phrase><phrase role="special">;</phrase>
</programlisting>
<variablelist>
<title></title>
<varlistentry>
<term>Returns:</term>
<listitem>
<para>
If <code><phrase role="special">*</phrase><phrase role="keyword">this</phrase></code>
refers to a fiber of execution, an instance of <link linkend="class_fiber_id"><code><phrase
role="identifier">fiber</phrase><phrase role="special">::</phrase><phrase
role="identifier">id</phrase></code></link> that represents that fiber. Otherwise
returns a default-constructed <link linkend="class_fiber_id"><code><phrase role="identifier">fiber</phrase><phrase
role="special">::</phrase><phrase role="identifier">id</phrase></code></link>.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>Throws:</term>
<listitem>
<para>
Nothing
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>See also:</term>
<listitem>
<para>
<link linkend="fiber_get_id"><code>fiber::get_id()</code></link>
</para>
</listitem>
</varlistentry>
</variablelist>
<para>
<bridgehead renderas="sect4" id="context_attach_bridgehead">
<phrase id="context_attach"/>
<link linkend="context_attach">Member function <code>attach</code>()</link>
</bridgehead>
</para>
<programlisting><phrase role="keyword">void</phrase> <phrase role="identifier">attach</phrase><phrase role="special">(</phrase> <phrase role="identifier">context</phrase> <phrase role="special">*</phrase> <phrase role="identifier">f</phrase><phrase role="special">)</phrase> <phrase role="keyword">noexcept</phrase><phrase role="special">;</phrase>
</programlisting>
<variablelist>
<title></title>
<varlistentry>
<term>Precondition:</term>
<listitem>
<para>
<code><phrase role="keyword">this</phrase><phrase role="special">-&gt;</phrase><phrase
role="identifier">get_scheduler</phrase><phrase role="special">()</phrase>
<phrase role="special">==</phrase> <phrase role="keyword">nullptr</phrase></code>
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>Effects:</term>
<listitem>
<para>
Attach fiber <code><phrase role="identifier">f</phrase></code> to scheduler
running <code><phrase role="special">*</phrase><phrase role="keyword">this</phrase></code>.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>Postcondition:</term>
<listitem>
<para>
<code><phrase role="keyword">this</phrase><phrase role="special">-&gt;</phrase><phrase
role="identifier">get_scheduler</phrase><phrase role="special">()</phrase>
<phrase role="special">!=</phrase> <phrase role="keyword">nullptr</phrase></code>
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>Throws:</term>
<listitem>
<para>
Nothing
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>Note:</term>
<listitem>
<para>
A typical call: <code><phrase role="identifier">boost</phrase><phrase
role="special">::</phrase><phrase role="identifier">fibers</phrase><phrase
role="special">::</phrase><phrase role="identifier">context</phrase><phrase
role="special">::</phrase><phrase role="identifier">active</phrase><phrase
role="special">()-&gt;</phrase><phrase role="identifier">attach</phrase><phrase
role="special">(</phrase><phrase role="identifier">f</phrase><phrase
role="special">);</phrase></code>
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>Note:</term>
<listitem>
<para>
<code><phrase role="identifier">f</phrase></code> must not be the running
fiber&#8217;s context. It must not be <link linkend="blocking"><emphasis>blocked</emphasis></link>
or terminated. It must not be a <code><phrase role="identifier">pinned_context</phrase></code>.
It must be currently detached. It must not currently be linked into an
<link linkend="class_algorithm"><code>algorithm</code></link> implementation&#8217;s ready queue. Most of these conditions
are implied by <code><phrase role="identifier">f</phrase></code> being
owned by an <code><phrase role="identifier">algorithm</phrase></code>
implementation: that is, it has been passed to <link linkend="algorithm_awakened"><code>algorithm::awakened()</code></link> but
has not yet been returned by <link linkend="algorithm_pick_next"><code>algorithm::pick_next()</code></link>.
Typically a <code><phrase role="identifier">pick_next</phrase><phrase
role="special">()</phrase></code> implementation would call <code><phrase
role="identifier">attach</phrase><phrase role="special">()</phrase></code>
with the <code><phrase role="identifier">context</phrase><phrase role="special">*</phrase></code>
it is about to return. It must first remove <code><phrase role="identifier">f</phrase></code>
from its ready queue. You should never pass a <code><phrase role="identifier">pinned_context</phrase></code>
to <code><phrase role="identifier">attach</phrase><phrase role="special">()</phrase></code>
because you should never have called its <code><phrase role="identifier">detach</phrase><phrase
role="special">()</phrase></code> method in the first place.
</para>
</listitem>
</varlistentry>
</variablelist>
<para>
<bridgehead renderas="sect4" id="context_detach_bridgehead">
<phrase id="context_detach"/>
<link linkend="context_detach">Member function <code>detach</code>()</link>
</bridgehead>
</para>
<programlisting><phrase role="keyword">void</phrase> <phrase role="identifier">detach</phrase><phrase role="special">()</phrase> <phrase role="keyword">noexcept</phrase><phrase role="special">;</phrase>
</programlisting>
<variablelist>
<title></title>
<varlistentry>
<term>Precondition:</term>
<listitem>
<para>
<code><phrase role="special">(</phrase><phrase role="keyword">this</phrase><phrase
role="special">-&gt;</phrase><phrase role="identifier">get_scheduler</phrase><phrase
role="special">()</phrase> <phrase role="special">!=</phrase> <phrase
role="keyword">nullptr</phrase><phrase role="special">)</phrase> <phrase
role="special">&amp;&amp;</phrase> <phrase role="special">!</phrase>
<phrase role="keyword">this</phrase><phrase role="special">-&gt;</phrase><phrase
role="identifier">is_context</phrase><phrase role="special">(</phrase><phrase
role="identifier">pinned_context</phrase><phrase role="special">)</phrase></code>
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>Effects:</term>
<listitem>
<para>
Detach fiber <code><phrase role="special">*</phrase><phrase role="keyword">this</phrase></code>
from its scheduler running <code><phrase role="special">*</phrase><phrase
role="keyword">this</phrase></code>.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>Throws:</term>
<listitem>
<para>
Nothing
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>Postcondition:</term>
<listitem>
<para>
<code><phrase role="keyword">this</phrase><phrase role="special">-&gt;</phrase><phrase
role="identifier">get_scheduler</phrase><phrase role="special">()</phrase>
<phrase role="special">==</phrase> <phrase role="keyword">nullptr</phrase></code>
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>Note:</term>
<listitem>
<para>
This method must be called on the thread with which the fiber is currently
associated. <code><phrase role="special">*</phrase><phrase role="keyword">this</phrase></code>
must not be the running fiber&#8217;s context. It must not be <link linkend="blocking"><emphasis>blocked</emphasis></link>
or terminated. It must not be a <code><phrase role="identifier">pinned_context</phrase></code>.
It must not be detached already. It must not already be linked into an
<link linkend="class_algorithm"><code>algorithm</code></link> implementation&#8217;s ready queue. Most of these conditions
are implied by <code><phrase role="special">*</phrase><phrase role="keyword">this</phrase></code>
being passed to <link linkend="algorithm_awakened"><code>algorithm::awakened()</code></link>; an <code><phrase
role="identifier">awakened</phrase><phrase role="special">()</phrase></code>
implementation must, however, test for <code><phrase role="identifier">pinned_context</phrase></code>.
It must call <code><phrase role="identifier">detach</phrase><phrase role="special">()</phrase></code>
<emphasis>before</emphasis> linking <code><phrase role="special">*</phrase><phrase
role="keyword">this</phrase></code> into its ready queue.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>Note:</term>
<listitem>
<para>
In particular, it is erroneous to attempt to migrate a fiber from one
thread to another by calling both <code><phrase role="identifier">detach</phrase><phrase
role="special">()</phrase></code> and <code><phrase role="identifier">attach</phrase><phrase
role="special">()</phrase></code> in the <link linkend="algorithm_pick_next"><code>algorithm::pick_next()</code></link> method.
<code><phrase role="identifier">pick_next</phrase><phrase role="special">()</phrase></code>
is called on the intended destination thread. <code><phrase role="identifier">detach</phrase><phrase
role="special">()</phrase></code> must be called on the fiber&#8217;s original
thread. You must call <code><phrase role="identifier">detach</phrase><phrase
role="special">()</phrase></code> in the corresponding <code><phrase
role="identifier">awakened</phrase><phrase role="special">()</phrase></code>
method.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>Note:</term>
<listitem>
<para>
Unless you intend make a fiber available for potential migration to a
different thread, you should call neither <code><phrase role="identifier">detach</phrase><phrase
role="special">()</phrase></code> nor <code><phrase role="identifier">attach</phrase><phrase
role="special">()</phrase></code> with its <code><phrase role="identifier">context</phrase></code>.
</para>
</listitem>
</varlistentry>
</variablelist>
<para>
<bridgehead renderas="sect4" id="context_is_context_bridgehead">
<phrase id="context_is_context"/>
<link linkend="context_is_context">Member function
<code>is_context</code>()</link>
</bridgehead>
</para>
<programlisting><phrase role="keyword">bool</phrase> <phrase role="identifier">is_context</phrase><phrase role="special">(</phrase> <phrase role="identifier">type</phrase> <phrase role="identifier">t</phrase><phrase role="special">)</phrase> <phrase role="keyword">const</phrase> <phrase role="keyword">noexcept</phrase><phrase role="special">;</phrase>
</programlisting>
<variablelist>
<title></title>
<varlistentry>
<term>Returns:</term>
<listitem>
<para>
<code><phrase role="keyword">true</phrase></code> if <code><phrase role="special">*</phrase><phrase
role="keyword">this</phrase></code> is of the specified type.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>Throws:</term>
<listitem>
<para>
Nothing
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>Note:</term>
<listitem>
<para>
<code><phrase role="identifier">type</phrase><phrase role="special">::</phrase><phrase
role="identifier">worker_context</phrase></code> here means any fiber
not special to the library. For <code><phrase role="identifier">type</phrase><phrase
role="special">::</phrase><phrase role="identifier">main_context</phrase></code>
the <code><phrase role="identifier">context</phrase></code> is associated
with the <quote>main</quote> fiber of the thread: the one implicitly
created by the thread itself, rather than one explicitly created by
<emphasis role="bold">Boost.Fiber</emphasis>. For <code><phrase role="identifier">type</phrase><phrase
role="special">::</phrase><phrase role="identifier">dispatcher_context</phrase></code>
the <code><phrase role="identifier">context</phrase></code> is associated
with a <quote>dispatching</quote> fiber, responsible for dispatching
awakened fibers to a scheduler&#8217;s ready-queue. The <quote>dispatching</quote>
fiber is an implementation detail of the fiber manager. The context of
the <quote>main</quote> or <quote>dispatching</quote> fiber &mdash; any fiber
for which <code><phrase role="identifier">is_context</phrase><phrase
role="special">(</phrase><phrase role="identifier">pinned_context</phrase><phrase
role="special">)</phrase></code> is <code><phrase role="keyword">true</phrase></code>
&mdash; must never be passed to <link linkend="context_detach"><code>context::detach()</code></link>.
</para>
</listitem>
</varlistentry>
</variablelist>
<para>
<bridgehead renderas="sect4" id="context_is_terminated_bridgehead">
<phrase id="context_is_terminated"/>
<link linkend="context_is_terminated">Member
function <code>is_terminated</code>()</link>
</bridgehead>
</para>
<programlisting><phrase role="keyword">bool</phrase> <phrase role="identifier">is_terminated</phrase><phrase role="special">()</phrase> <phrase role="keyword">const</phrase> <phrase role="keyword">noexcept</phrase><phrase role="special">;</phrase>
</programlisting>
<variablelist>
<title></title>
<varlistentry>
<term>Returns:</term>
<listitem>
<para>
<code><phrase role="keyword">true</phrase></code> if <code><phrase role="special">*</phrase><phrase
role="keyword">this</phrase></code> is no longer a valid context.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>Throws:</term>
<listitem>
<para>
Nothing
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>Note:</term>
<listitem>
<para>
The <code><phrase role="identifier">context</phrase></code> has returned
from its fiber-function and is no longer considered a valid context.
</para>
</listitem>
</varlistentry>
</variablelist>
<para>
<bridgehead renderas="sect4" id="context_ready_is_linked_bridgehead">
<phrase id="context_ready_is_linked"/>
<link linkend="context_ready_is_linked">Member
function <code>ready_is_linked</code>()</link>
</bridgehead>
</para>
<programlisting><phrase role="keyword">bool</phrase> <phrase role="identifier">ready_is_linked</phrase><phrase role="special">()</phrase> <phrase role="keyword">const</phrase> <phrase role="keyword">noexcept</phrase><phrase role="special">;</phrase>
</programlisting>
<variablelist>
<title></title>
<varlistentry>
<term>Returns:</term>
<listitem>
<para>
<code><phrase role="keyword">true</phrase></code> if <code><phrase role="special">*</phrase><phrase
role="keyword">this</phrase></code> is stored in an <link linkend="class_algorithm"><code>algorithm</code></link>
implementation&#8217;s
ready-queue.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>Throws:</term>
<listitem>
<para>
Nothing
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>Note:</term>
<listitem>
<para>
Specifically, this method indicates whether <link linkend="context_ready_link"><code>context::ready_link()</code></link> has
been called on <code><phrase role="special">*</phrase><phrase role="keyword">this</phrase></code>.
<code><phrase role="identifier">ready_is_linked</phrase><phrase role="special">()</phrase></code>
has no information about participation in any other containers.
</para>
</listitem>
</varlistentry>
</variablelist>
<para>
<bridgehead renderas="sect4" id="context_remote_ready_is_linked_bridgehead">
<phrase id="context_remote_ready_is_linked"/>
<link linkend="context_remote_ready_is_linked">Member
function <code>remote_ready_is_linked</code>()</link>
</bridgehead>
</para>
<programlisting><phrase role="keyword">bool</phrase> <phrase role="identifier">remote_ready_is_linked</phrase><phrase role="special">()</phrase> <phrase role="keyword">const</phrase> <phrase role="keyword">noexcept</phrase><phrase role="special">;</phrase>
</programlisting>
<variablelist>
<title></title>
<varlistentry>
<term>Returns:</term>
<listitem>
<para>
<code><phrase role="keyword">true</phrase></code> if <code><phrase role="special">*</phrase><phrase
role="keyword">this</phrase></code> is stored in the fiber manager&#8217;s remote-ready-queue.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>Throws:</term>
<listitem>
<para>
Nothing
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>Note:</term>
<listitem>
<para>
A <code><phrase role="identifier">context</phrase></code> signaled as
ready by another thread is first stored in the fiber manager&#8217;s remote-ready-queue.
This is the mechanism by which the fiber manager protects an <link linkend="class_algorithm"><code>algorithm</code></link> implementation
from cross-thread <link linkend="algorithm_awakened"><code>algorithm::awakened()</code></link> calls.
</para>
</listitem>
</varlistentry>
</variablelist>
<para>
<bridgehead renderas="sect4" id="context_wait_is_linked_bridgehead">
<phrase id="context_wait_is_linked"/>
<link linkend="context_wait_is_linked">Member
function <code>wait_is_linked</code>()</link>
</bridgehead>
</para>
<programlisting><phrase role="keyword">bool</phrase> <phrase role="identifier">wait_is_linked</phrase><phrase role="special">()</phrase> <phrase role="keyword">const</phrase> <phrase role="keyword">noexcept</phrase><phrase role="special">;</phrase>
</programlisting>
<variablelist>
<title></title>
<varlistentry>
<term>Returns:</term>
<listitem>
<para>
<code><phrase role="keyword">true</phrase></code> if <code><phrase role="special">*</phrase><phrase
role="keyword">this</phrase></code> is stored in the wait-queue of some
synchronization object.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>Throws:</term>
<listitem>
<para>
Nothing
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>Note:</term>
<listitem>
<para>
The <code><phrase role="identifier">context</phrase></code> of a fiber
waiting on a synchronization object (e.g. <code><phrase role="identifier">mutex</phrase></code>,
<code><phrase role="identifier">condition_variable</phrase></code> etc.)
is stored in the wait-queue of that synchronization object.
</para>
</listitem>
</varlistentry>
</variablelist>
<para>
<bridgehead renderas="sect4" id="context_ready_link_bridgehead">
<phrase id="context_ready_link"/>
<link linkend="context_ready_link">Member function
<code>ready_link</code>()</link>
</bridgehead>
</para>
<programlisting><phrase role="keyword">template</phrase><phrase role="special">&lt;</phrase> <phrase role="keyword">typename</phrase> <phrase role="identifier">List</phrase> <phrase role="special">&gt;</phrase>
<phrase role="keyword">void</phrase> <phrase role="identifier">ready_link</phrase><phrase role="special">(</phrase> <phrase role="identifier">List</phrase> <phrase role="special">&amp;</phrase> <phrase role="identifier">lst</phrase><phrase role="special">)</phrase> <phrase role="keyword">noexcept</phrase><phrase role="special">;</phrase>
</programlisting>
<variablelist>
<title></title>
<varlistentry>
<term>Effects:</term>
<listitem>
<para>
Stores <code><phrase role="special">*</phrase><phrase role="keyword">this</phrase></code>
in ready-queue <code><phrase role="identifier">lst</phrase></code>.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>Throws:</term>
<listitem>
<para>
Nothing
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>Note:</term>
<listitem>
<para>
Argument <code><phrase role="identifier">lst</phrase></code> must be
a doubly-linked list from <ulink url="http://www.boost.org/doc/libs/release/libs/intrusive/index.html">Boost.Intrusive</ulink>,
e.g. an instance of <code><phrase role="identifier">boost</phrase><phrase
role="special">::</phrase><phrase role="identifier">fibers</phrase><phrase
role="special">::</phrase><phrase role="identifier">scheduler</phrase><phrase
role="special">::</phrase><phrase role="identifier">ready_queue_t</phrase></code>.
Specifically, it must be a <ulink url="http://www.boost.org/doc/libs/release/doc/html/intrusive/list.html"><code><phrase
role="identifier">boost</phrase><phrase role="special">::</phrase><phrase
role="identifier">intrusive</phrase><phrase role="special">::</phrase><phrase
role="identifier">list</phrase></code></ulink> compatible with the <code><phrase
role="identifier">list_member_hook</phrase></code> stored in the <code><phrase
role="identifier">context</phrase></code> object.
</para>
</listitem>
</varlistentry>
</variablelist>
<para>
<bridgehead renderas="sect4" id="context_remote_ready_link_bridgehead">
<phrase id="context_remote_ready_link"/>
<link linkend="context_remote_ready_link">Member
function <code>remote_ready_link</code>()</link>
</bridgehead>
</para>
<programlisting><phrase role="keyword">template</phrase><phrase role="special">&lt;</phrase> <phrase role="keyword">typename</phrase> <phrase role="identifier">List</phrase> <phrase role="special">&gt;</phrase>
<phrase role="keyword">void</phrase> <phrase role="identifier">remote_ready_link</phrase><phrase role="special">(</phrase> <phrase role="identifier">List</phrase> <phrase role="special">&amp;</phrase> <phrase role="identifier">lst</phrase><phrase role="special">)</phrase> <phrase role="keyword">noexcept</phrase><phrase role="special">;</phrase>
</programlisting>
<variablelist>
<title></title>
<varlistentry>
<term>Effects:</term>
<listitem>
<para>
Stores <code><phrase role="special">*</phrase><phrase role="keyword">this</phrase></code>
in remote-ready-queue <code><phrase role="identifier">lst</phrase></code>.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>Throws:</term>
<listitem>
<para>
Nothing
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>Note:</term>
<listitem>
<para>
Argument <code><phrase role="identifier">lst</phrase></code> must be
a doubly-linked list from <ulink url="http://www.boost.org/doc/libs/release/libs/intrusive/index.html">Boost.Intrusive</ulink>.
</para>
</listitem>
</varlistentry>
</variablelist>
<para>
<bridgehead renderas="sect4" id="context_wait_link_bridgehead">
<phrase id="context_wait_link"/>
<link linkend="context_wait_link">Member function
<code>wait_link</code>()</link>
</bridgehead>
</para>
<programlisting><phrase role="keyword">template</phrase><phrase role="special">&lt;</phrase> <phrase role="keyword">typename</phrase> <phrase role="identifier">List</phrase> <phrase role="special">&gt;</phrase>
<phrase role="keyword">void</phrase> <phrase role="identifier">wait_link</phrase><phrase role="special">(</phrase> <phrase role="identifier">List</phrase> <phrase role="special">&amp;</phrase> <phrase role="identifier">lst</phrase><phrase role="special">)</phrase> <phrase role="keyword">noexcept</phrase><phrase role="special">;</phrase>
</programlisting>
<variablelist>
<title></title>
<varlistentry>
<term>Effects:</term>
<listitem>
<para>
Stores <code><phrase role="special">*</phrase><phrase role="keyword">this</phrase></code>
in wait-queue <code><phrase role="identifier">lst</phrase></code>.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>Throws:</term>
<listitem>
<para>
Nothing
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>Note:</term>
<listitem>
<para>
Argument <code><phrase role="identifier">lst</phrase></code> must be
a doubly-linked list from <ulink url="http://www.boost.org/doc/libs/release/libs/intrusive/index.html">Boost.Intrusive</ulink>.
</para>
</listitem>
</varlistentry>
</variablelist>
<para>
<bridgehead renderas="sect4" id="context_ready_unlink_bridgehead">
<phrase id="context_ready_unlink"/>
<link linkend="context_ready_unlink">Member
function <code>ready_unlink</code>()</link>
</bridgehead>
</para>
<programlisting><phrase role="keyword">void</phrase> <phrase role="identifier">ready_unlink</phrase><phrase role="special">()</phrase> <phrase role="keyword">noexcept</phrase><phrase role="special">;</phrase>
</programlisting>
<variablelist>
<title></title>
<varlistentry>
<term>Effects:</term>
<listitem>
<para>
Removes <code><phrase role="special">*</phrase><phrase role="keyword">this</phrase></code>
from ready-queue: undoes the effect of <link linkend="context_ready_link"><code>context::ready_link()</code></link>.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>Throws:</term>
<listitem>
<para>
Nothing
</para>
</listitem>
</varlistentry>
</variablelist>
<para>
<bridgehead renderas="sect4" id="context_remote_ready_unlink_bridgehead">
<phrase id="context_remote_ready_unlink"/>
<link linkend="context_remote_ready_unlink">Member
function <code>remote_ready_unlink</code>()</link>
</bridgehead>
</para>
<programlisting><phrase role="keyword">void</phrase> <phrase role="identifier">remote_ready_unlink</phrase><phrase role="special">()</phrase> <phrase role="keyword">noexcept</phrase><phrase role="special">;</phrase>
</programlisting>
<variablelist>
<title></title>
<varlistentry>
<term>Effects:</term>
<listitem>
<para>
Removes <code><phrase role="special">*</phrase><phrase role="keyword">this</phrase></code>
from remote-ready-queue.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>Throws:</term>
<listitem>
<para>
Nothing
</para>
</listitem>
</varlistentry>
</variablelist>
<para>
<bridgehead renderas="sect4" id="context_wait_unlink_bridgehead">
<phrase id="context_wait_unlink"/>
<link linkend="context_wait_unlink">Member
function <code>wait_unlink</code>()</link>
</bridgehead>
</para>
<programlisting><phrase role="keyword">void</phrase> <phrase role="identifier">wait_unlink</phrase><phrase role="special">()</phrase> <phrase role="keyword">noexcept</phrase><phrase role="special">;</phrase>
</programlisting>
<variablelist>
<title></title>
<varlistentry>
<term>Effects:</term>
<listitem>
<para>
Removes <code><phrase role="special">*</phrase><phrase role="keyword">this</phrase></code>
from wait-queue.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>Throws:</term>
<listitem>
<para>
Nothing
</para>
</listitem>
</varlistentry>
</variablelist>
<para>
<bridgehead renderas="sect4" id="context_suspend_bridgehead">
<phrase id="context_suspend"/>
<link linkend="context_suspend">Member function <code>suspend</code>()</link>
</bridgehead>
</para>
<programlisting><phrase role="keyword">void</phrase> <phrase role="identifier">suspend</phrase><phrase role="special">()</phrase> <phrase role="keyword">noexcept</phrase><phrase role="special">;</phrase>
</programlisting>
<variablelist>
<title></title>
<varlistentry>
<term>Effects:</term>
<listitem>
<para>
Suspends the running fiber (the fiber associated with <code><phrase role="special">*</phrase><phrase
role="keyword">this</phrase></code>) until some other fiber passes <code><phrase
role="keyword">this</phrase></code> to <link linkend="context_schedule"><code>context::schedule()</code></link>.
<code><phrase role="special">*</phrase><phrase role="keyword">this</phrase></code>
is marked as not-ready, and control passes to the scheduler to select
another fiber to run.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>Throws:</term>
<listitem>
<para>
Nothing
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>Note:</term>
<listitem>
<para>
This is a low-level API potentially useful for integration with other
frameworks. It is not intended to be directly invoked by a typical application
program.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>Note:</term>
<listitem>
<para>
The burden is on the caller to arrange for a call to <code><phrase role="identifier">schedule</phrase><phrase
role="special">()</phrase></code> with a pointer to <code><phrase role="keyword">this</phrase></code>
at some future time.
</para>
</listitem>
</varlistentry>
</variablelist>
<para>
<bridgehead renderas="sect4" id="context_schedule_bridgehead">
<phrase id="context_schedule"/>
<link linkend="context_schedule">Member function
<code>schedule</code>()</link>
</bridgehead>
</para>
<programlisting><phrase role="keyword">void</phrase> <phrase role="identifier">schedule</phrase><phrase role="special">(</phrase> <phrase role="identifier">context</phrase> <phrase role="special">*</phrase> <phrase role="identifier">ctx</phrase> <phrase role="special">)</phrase> <phrase role="keyword">noexcept</phrase><phrase role="special">;</phrase>
</programlisting>
<variablelist>
<title></title>
<varlistentry>
<term>Effects:</term>
<listitem>
<para>
Mark the fiber associated with context <code><phrase role="special">*</phrase><phrase
role="identifier">ctx</phrase></code> as being ready to run. This does
not immediately resume that fiber; rather it passes the fiber to the
scheduler for subsequent resumption. If the scheduler is idle (has not
returned from a call to <link linkend="algorithm_suspend_until"><code>algorithm::suspend_until()</code></link>),
<link linkend="algorithm_notify"><code>algorithm::notify()</code></link> is called to wake it up.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>Throws:</term>
<listitem>
<para>
Nothing
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>Note:</term>
<listitem>
<para>
This is a low-level API potentially useful for integration with other
frameworks. It is not intended to be directly invoked by a typical application
program.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>Note:</term>
<listitem>
<para>
It is explicitly supported to call <code><phrase role="identifier">schedule</phrase><phrase
role="special">(</phrase><phrase role="identifier">ctx</phrase><phrase
role="special">)</phrase></code> from a thread other than the one on
which <code><phrase role="special">*</phrase><phrase role="identifier">ctx</phrase></code>
is currently suspended. The corresponding fiber will be resumed on its
original thread in due course.
</para>
</listitem>
</varlistentry>
</variablelist>
<para>
<bridgehead renderas="sect4" id="context_less_bridgehead">
<phrase id="context_less"/>
<link linkend="context_less">Non-member function <code>operator&lt;()</code></link>
</bridgehead>
</para>
<programlisting><phrase role="keyword">bool</phrase> <phrase role="keyword">operator</phrase><phrase role="special">&lt;(</phrase> <phrase role="identifier">context</phrase> <phrase role="keyword">const</phrase><phrase role="special">&amp;</phrase> <phrase role="identifier">l</phrase><phrase role="special">,</phrase> <phrase role="identifier">context</phrase> <phrase role="keyword">const</phrase><phrase role="special">&amp;</phrase> <phrase role="identifier">r</phrase><phrase role="special">)</phrase> <phrase role="keyword">noexcept</phrase><phrase role="special">;</phrase>
</programlisting>
<variablelist>
<title></title>
<varlistentry>
<term>Returns:</term>
<listitem>
<para>
<code><phrase role="keyword">true</phrase></code> if <code><phrase role="identifier">l</phrase><phrase
role="special">.</phrase><phrase role="identifier">get_id</phrase><phrase
role="special">()</phrase> <phrase role="special">&lt;</phrase> <phrase
role="identifier">r</phrase><phrase role="special">.</phrase><phrase
role="identifier">get_id</phrase><phrase role="special">()</phrase></code>
is <code><phrase role="keyword">true</phrase></code>, <code><phrase role="keyword">false</phrase></code>
otherwise.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>Throws:</term>
<listitem>
<para>
Nothing.
</para>
</listitem>
</varlistentry>
</variablelist>
</section>
<section id="fiber.stack">
<title><anchor id="stack"/><link linkend="fiber.stack">Stack allocation</link></title>
<para>
A <link linkend="class_fiber"><code>fiber</code></link> uses internally an __econtext__ which manages a set of registers
and a stack. The memory used by the stack is allocated/deallocated via a <emphasis>stack_allocator</emphasis>
which is required to model a <link linkend="stack_allocator_concept"><emphasis>stack-allocator
concept</emphasis></link>.
</para>
<para>
A <emphasis>stack_allocator</emphasis> can be passed to <link linkend="fiber_fiber"><code><phrase
role="identifier">fiber</phrase><phrase role="special">::</phrase><phrase role="identifier">fiber</phrase><phrase
role="special">()</phrase></code></link> or to <link linkend="fibers_async"><code>fibers::async()</code></link>.
</para>
<anchor id="stack_allocator_concept"/>
<bridgehead renderas="sect3" id="fiber.stack.h0">
<phrase id="fiber.stack.stack_allocator_concept"/><link linkend="fiber.stack.stack_allocator_concept">stack-allocator
concept</link>
</bridgehead>
<para>
A <emphasis>stack_allocator</emphasis> must satisfy the <emphasis>stack-allocator
concept</emphasis> requirements shown in the following table, in which <code><phrase
role="identifier">a</phrase></code> is an object of a <emphasis>stack_allocator</emphasis>
type, <code><phrase role="identifier">sctx</phrase></code> is a <ulink url="http://www.boost.org/doc/libs/release/libs/context/doc/html/context/stack/stack_context.html"><code><phrase
role="identifier">stack_context</phrase></code></ulink>, and <code><phrase
role="identifier">size</phrase></code> is a <code><phrase role="identifier">std</phrase><phrase
role="special">::</phrase><phrase role="identifier">size_t</phrase></code>:
</para>
<informaltable frame="all">
<tgroup cols="3">
<thead>
<row>
<entry>
<para>
expression
</para>
</entry>
<entry>
<para>
return type
</para>
</entry>
<entry>
<para>
notes
</para>
</entry>
</row>
</thead>
<tbody>
<row>
<entry>
<para>
<code><phrase role="identifier">a</phrase><phrase role="special">(</phrase><phrase
role="identifier">size</phrase><phrase role="special">)</phrase></code>
</para>
</entry>
<entry>
</entry>
<entry>
<para>
creates a stack allocator
</para>
</entry>
</row>
<row>
<entry>
<para>
<code><phrase role="identifier">a</phrase><phrase role="special">.</phrase><phrase
role="identifier">allocate</phrase><phrase role="special">()</phrase></code>
</para>
</entry>
<entry>
<para>
<ulink url="http://www.boost.org/doc/libs/release/libs/context/doc/html/context/stack/stack_context.html"><code><phrase
role="identifier">stack_context</phrase></code></ulink>
</para>
</entry>
<entry>
<para>
creates a stack
</para>
</entry>
</row>
<row>
<entry>
<para>
<code><phrase role="identifier">a</phrase><phrase role="special">.</phrase><phrase
role="identifier">deallocate</phrase><phrase role="special">(</phrase>
<phrase role="identifier">sctx</phrase><phrase role="special">)</phrase></code>
</para>
</entry>
<entry>
<para>
<code><phrase role="keyword">void</phrase></code>
</para>
</entry>
<entry>
<para>
deallocates the stack created by <code><phrase role="identifier">a</phrase><phrase
role="special">.</phrase><phrase role="identifier">allocate</phrase><phrase
role="special">()</phrase></code>
</para>
</entry>
</row>
</tbody>
</tgroup>
</informaltable>
<important>
<para>
The implementation of <code><phrase role="identifier">allocate</phrase><phrase
role="special">()</phrase></code> might include logic to protect against
exceeding the context's available stack size rather than leaving it as undefined
behaviour.
</para>
</important>
<important>
<para>
Calling <code><phrase role="identifier">deallocate</phrase><phrase role="special">()</phrase></code>
with a <ulink url="http://www.boost.org/doc/libs/release/libs/context/doc/html/context/stack/stack_context.html"><code><phrase
role="identifier">stack_context</phrase></code></ulink> not obtained from
<code><phrase role="identifier">allocate</phrase><phrase role="special">()</phrase></code>
results in undefined behaviour.
</para>
</important>
<note>
<para>
The memory for the stack is not required to be aligned; alignment takes place
inside __econtext__.
</para>
</note>
<para>
See also <ulink url="http://www.boost.org/doc/libs/release/libs/context/doc/html/context/stack.html">Boost.Context
stack allocation</ulink>. In particular, <code><phrase role="identifier">traits_type</phrase></code>
methods are as described for <ulink url="http://www.boost.org/doc/libs/release/libs/context/doc/html/context/stack/stack_traits.html"><code><phrase
role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">context</phrase><phrase
role="special">::</phrase><phrase role="identifier">stack_traits</phrase></code></ulink>.
</para>
<para>
<bridgehead renderas="sect4" id="class_protected_fixedsize_stack_bridgehead">
<phrase id="class_protected_fixedsize_stack"/>
<link linkend="class_protected_fixedsize_stack">Class
<code>protected_fixedsize_stack</code></link>
</bridgehead>
</para>
<para>
<emphasis role="bold">Boost.Fiber</emphasis> provides the class <link linkend="class_protected_fixedsize_stack"><code>protected_fixedsize_stack</code></link> which
models the <link linkend="stack_allocator_concept"><emphasis>stack-allocator
concept</emphasis></link>. It appends a guard page at the end of each stack
to protect against exceeding the stack. If the guard page is accessed (read
or write operation) a segmentation fault/access violation is generated by the
operating system.
</para>
<important>
<para>
Using <link linkend="class_protected_fixedsize_stack"><code>protected_fixedsize_stack</code></link> is expensive.
Launching a new fiber with a stack of this type incurs the overhead of setting
the memory protection; once allocated, this stack is just as efficient to
use as <link linkend="class_fixedsize_stack"><code>fixedsize_stack</code></link>.
</para>
</important>
<note>
<para>
The appended <code><phrase role="identifier">guard</phrase> <phrase role="identifier">page</phrase></code>
is <emphasis role="bold">not</emphasis> mapped to physical memory, only virtual
addresses are used.
</para>
</note>
<programlisting><phrase role="preprocessor">#include</phrase> <phrase role="special">&lt;</phrase><phrase role="identifier">boost</phrase><phrase role="special">/</phrase><phrase role="identifier">fiber</phrase><phrase role="special">/</phrase><phrase role="identifier">protected_fixedsize</phrase><phrase role="special">.</phrase><phrase role="identifier">hpp</phrase><phrase role="special">&gt;</phrase>
<phrase role="keyword">namespace</phrase> <phrase role="identifier">boost</phrase> <phrase role="special">{</phrase>
<phrase role="keyword">namespace</phrase> <phrase role="identifier">fibers</phrase> <phrase role="special">{</phrase>
<phrase role="keyword">struct</phrase> <phrase role="identifier">protected_fixedsize</phrase> <phrase role="special">{</phrase>
<phrase role="identifier">protected_fixesize</phrase><phrase role="special">(</phrase><phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">size_t</phrase> <phrase role="identifier">size</phrase> <phrase role="special">=</phrase> <phrase role="identifier">traits_type</phrase><phrase role="special">::</phrase><phrase role="identifier">default_size</phrase><phrase role="special">());</phrase>
<phrase role="identifier">stack_context</phrase> <phrase role="identifier">allocate</phrase><phrase role="special">();</phrase>
<phrase role="keyword">void</phrase> <phrase role="identifier">deallocate</phrase><phrase role="special">(</phrase> <phrase role="identifier">stack_context</phrase> <phrase role="special">&amp;);</phrase>
<phrase role="special">}</phrase>
<phrase role="special">}}</phrase>
</programlisting>
<para>
<bridgehead renderas="sect4" id="protected_fixedsize_allocate_bridgehead">
<phrase id="protected_fixedsize_allocate"/>
<link linkend="protected_fixedsize_allocate">Member
function <code>allocate</code>()</link>
</bridgehead>
</para>
<programlisting><phrase role="identifier">stack_context</phrase> <phrase role="identifier">allocate</phrase><phrase role="special">();</phrase>
</programlisting>
<variablelist>
<title></title>
<varlistentry>
<term>Preconditions:</term>
<listitem>
<para>
<code><phrase role="identifier">traits_type</phrase><phrase role="special">::</phrase><phrase
role="identifier">minimum_size</phrase><phrase role="special">()</phrase>
<phrase role="special">&lt;=</phrase> <phrase role="identifier">size</phrase></code>
and <code><phrase role="identifier">traits_type</phrase><phrase role="special">::</phrase><phrase
role="identifier">is_unbounded</phrase><phrase role="special">()</phrase>
<phrase role="special">||</phrase> <phrase role="special">(</phrase>
<phrase role="identifier">size</phrase> <phrase role="special">&lt;=</phrase>
<phrase role="identifier">traits_type</phrase><phrase role="special">::</phrase><phrase
role="identifier">maximum_size</phrase><phrase role="special">()</phrase>
<phrase role="special">)</phrase></code>.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>Effects:</term>
<listitem>
<para>
Allocates memory of at least <code><phrase role="identifier">size</phrase></code>
bytes and stores a pointer to the stack and its actual size in <code><phrase
role="identifier">sctx</phrase></code>. Depending on the architecture
(the stack grows downwards/upwards) the stored address is the highest/lowest
address of the stack.
</para>
</listitem>
</varlistentry>
</variablelist>
<para>
<bridgehead renderas="sect4" id="protected_fixesize_deallocate_bridgehead">
<phrase id="protected_fixesize_deallocate"/>
<link linkend="protected_fixesize_deallocate">Member
function <code>deallocate</code>()</link>
</bridgehead>
</para>
<programlisting><phrase role="keyword">void</phrase> <phrase role="identifier">deallocate</phrase><phrase role="special">(</phrase> <phrase role="identifier">stack_context</phrase> <phrase role="special">&amp;</phrase> <phrase role="identifier">sctx</phrase><phrase role="special">);</phrase>
</programlisting>
<variablelist>
<title></title>
<varlistentry>
<term>Preconditions:</term>
<listitem>
<para>
<code><phrase role="identifier">sctx</phrase><phrase role="special">.</phrase><phrase
role="identifier">sp</phrase></code> is valid, <code><phrase role="identifier">traits_type</phrase><phrase
role="special">::</phrase><phrase role="identifier">minimum_size</phrase><phrase
role="special">()</phrase> <phrase role="special">&lt;=</phrase> <phrase
role="identifier">sctx</phrase><phrase role="special">.</phrase><phrase
role="identifier">size</phrase></code> and <code><phrase role="identifier">traits_type</phrase><phrase
role="special">::</phrase><phrase role="identifier">is_unbounded</phrase><phrase
role="special">()</phrase> <phrase role="special">||</phrase> <phrase
role="special">(</phrase> <phrase role="identifier">sctx</phrase><phrase
role="special">.</phrase><phrase role="identifier">size</phrase> <phrase
role="special">&lt;=</phrase> <phrase role="identifier">traits_type</phrase><phrase
role="special">::</phrase><phrase role="identifier">maximum_size</phrase><phrase
role="special">()</phrase> <phrase role="special">)</phrase></code>.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>Effects:</term>
<listitem>
<para>
Deallocates the stack space.
</para>
</listitem>
</varlistentry>
</variablelist>
<para>
<bridgehead renderas="sect4" id="class_pooled_fixedsize_stack_bridgehead">
<phrase id="class_pooled_fixedsize_stack"/>
<link linkend="class_pooled_fixedsize_stack">Class
<code>pooled_fixedsize_stack</code></link>
</bridgehead>
</para>
<para>
<emphasis role="bold">Boost.Fiber</emphasis> provides the class <link linkend="class_pooled_fixedsize_stack"><code>pooled_fixedsize_stack</code></link> which
models the <link linkend="stack_allocator_concept"><emphasis>stack-allocator
concept</emphasis></link>. In contrast to <link linkend="class_protected_fixedsize_stack"><code>protected_fixedsize_stack</code></link> it
does not append a guard page at the end of each stack. The memory is managed
internally by <ulink url="http://www.boost.org/doc/libs/release/libs/pool/doc/html/boost/pool.html"><code><phrase
role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">pool</phrase><phrase
role="special">&lt;&gt;</phrase></code></ulink>.
</para>
<programlisting><phrase role="preprocessor">#include</phrase> <phrase role="special">&lt;</phrase><phrase role="identifier">boost</phrase><phrase role="special">/</phrase><phrase role="identifier">fiber</phrase><phrase role="special">/</phrase><phrase role="identifier">pooled_fixedsize_stack</phrase><phrase role="special">.</phrase><phrase role="identifier">hpp</phrase><phrase role="special">&gt;</phrase>
<phrase role="keyword">namespace</phrase> <phrase role="identifier">boost</phrase> <phrase role="special">{</phrase>
<phrase role="keyword">namespace</phrase> <phrase role="identifier">fibers</phrase> <phrase role="special">{</phrase>
<phrase role="keyword">struct</phrase> <phrase role="identifier">pooled_fixedsize_stack</phrase> <phrase role="special">{</phrase>
<phrase role="identifier">pooled_fixedsize_stack</phrase><phrase role="special">(</phrase><phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">size_t</phrase> <phrase role="identifier">stack_size</phrase> <phrase role="special">=</phrase> <phrase role="identifier">traits_type</phrase><phrase role="special">::</phrase><phrase role="identifier">default_size</phrase><phrase role="special">(),</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">size_t</phrase> <phrase role="identifier">next_size</phrase> <phrase role="special">=</phrase> <phrase role="number">32</phrase><phrase role="special">,</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">size_t</phrase> <phrase role="identifier">max_size</phrase> <phrase role="special">=</phrase> <phrase role="number">0</phrase><phrase role="special">);</phrase>
<phrase role="identifier">stack_context</phrase> <phrase role="identifier">allocate</phrase><phrase role="special">();</phrase>
<phrase role="keyword">void</phrase> <phrase role="identifier">deallocate</phrase><phrase role="special">(</phrase> <phrase role="identifier">stack_context</phrase> <phrase role="special">&amp;);</phrase>
<phrase role="special">}</phrase>
<phrase role="special">}}</phrase>
</programlisting>
<para>
<bridgehead renderas="sect4" id="pooled_fixedsize_bridgehead">
<phrase id="pooled_fixedsize"/>
<link linkend="pooled_fixedsize">Constructor</link>
</bridgehead>
</para>
<programlisting><phrase role="identifier">pooled_fixedsize_stack</phrase><phrase role="special">(</phrase><phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">size_t</phrase> <phrase role="identifier">stack_size</phrase><phrase role="special">,</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">size_t</phrase> <phrase role="identifier">next_size</phrase><phrase role="special">,</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">size_t</phrase> <phrase role="identifier">max_size</phrase><phrase role="special">);</phrase>
</programlisting>
<variablelist>
<title></title>
<varlistentry>
<term>Preconditions:</term>
<listitem>
<para>
<code><phrase role="identifier">traits_type</phrase><phrase role="special">::</phrase><phrase
role="identifier">is_unbounded</phrase><phrase role="special">()</phrase>
<phrase role="special">||</phrase> <phrase role="special">(</phrase>
<phrase role="identifier">traits_type</phrase><phrase role="special">::</phrase><phrase
role="identifier">maximum_size</phrase><phrase role="special">()</phrase>
<phrase role="special">&gt;=</phrase> <phrase role="identifier">stack_size</phrase><phrase
role="special">)</phrase></code> and <code><phrase role="number">0</phrase>
<phrase role="special">&lt;</phrase> <phrase role="identifier">next_size</phrase></code>.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>Effects:</term>
<listitem>
<para>
Allocates memory of at least <code><phrase role="identifier">stack_size</phrase></code>
bytes and stores a pointer to the stack and its actual size in <code><phrase
role="identifier">sctx</phrase></code>. Depending on the architecture
(the stack grows downwards/upwards) the stored address is the highest/lowest
address of the stack. Argument <code><phrase role="identifier">next_size</phrase></code>
determines the number of stacks to request from the system the first
time that <code><phrase role="special">*</phrase><phrase role="keyword">this</phrase></code>
needs to allocate system memory. The third argument <code><phrase role="identifier">max_size</phrase></code>
controls how much memory might be allocated for stacks &mdash; a value of zero
means no upper limit.
</para>
</listitem>
</varlistentry>
</variablelist>
<para>
<bridgehead renderas="sect4" id="pooled_fixedsize_allocate_bridgehead">
<phrase id="pooled_fixedsize_allocate"/>
<link linkend="pooled_fixedsize_allocate">Member
function <code>allocate</code>()</link>
</bridgehead>
</para>
<programlisting><phrase role="identifier">stack_context</phrase> <phrase role="identifier">allocate</phrase><phrase role="special">();</phrase>
</programlisting>
<variablelist>
<title></title>
<varlistentry>
<term>Preconditions:</term>
<listitem>
<para>
<code><phrase role="identifier">traits_type</phrase><phrase role="special">::</phrase><phrase
role="identifier">is_unbounded</phrase><phrase role="special">()</phrase>
<phrase role="special">||</phrase> <phrase role="special">(</phrase>
<phrase role="identifier">traits_type</phrase><phrase role="special">::</phrase><phrase
role="identifier">maximum_size</phrase><phrase role="special">()</phrase>
<phrase role="special">&gt;=</phrase> <phrase role="identifier">stack_size</phrase><phrase
role="special">)</phrase></code>.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>Effects:</term>
<listitem>
<para>
Allocates memory of at least <code><phrase role="identifier">stack_size</phrase></code>
bytes and stores a pointer to the stack and its actual size in <code><phrase
role="identifier">sctx</phrase></code>. Depending on the architecture
(the stack grows downwards/upwards) the stored address is the highest/lowest
address of the stack.
</para>
</listitem>
</varlistentry>
</variablelist>
<para>
<bridgehead renderas="sect4" id="pooled_fixesize_deallocate_bridgehead">
<phrase id="pooled_fixesize_deallocate"/>
<link linkend="pooled_fixesize_deallocate">Member
function <code>deallocate</code>()</link>
</bridgehead>
</para>
<programlisting><phrase role="keyword">void</phrase> <phrase role="identifier">deallocate</phrase><phrase role="special">(</phrase> <phrase role="identifier">stack_context</phrase> <phrase role="special">&amp;</phrase> <phrase role="identifier">sctx</phrase><phrase role="special">);</phrase>
</programlisting>
<variablelist>
<title></title>
<varlistentry>
<term>Preconditions:</term>
<listitem>
<para>
<code><phrase role="identifier">sctx</phrase><phrase role="special">.</phrase><phrase
role="identifier">sp</phrase></code> is valid, <code><phrase role="identifier">traits_type</phrase><phrase
role="special">::</phrase><phrase role="identifier">is_unbounded</phrase><phrase
role="special">()</phrase> <phrase role="special">||</phrase> <phrase
role="special">(</phrase> <phrase role="identifier">traits_type</phrase><phrase
role="special">::</phrase><phrase role="identifier">maximum_size</phrase><phrase
role="special">()</phrase> <phrase role="special">&gt;=</phrase> <phrase
role="identifier">sctx</phrase><phrase role="special">.</phrase><phrase
role="identifier">size</phrase><phrase role="special">)</phrase></code>.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>Effects:</term>
<listitem>
<para>
Deallocates the stack space.
</para>
</listitem>
</varlistentry>
</variablelist>
<note>
<para>
This stack allocator is not thread safe.
</para>
</note>
<para>
<bridgehead renderas="sect4" id="class_fixedsize_stack_bridgehead">
<phrase id="class_fixedsize_stack"/>
<link linkend="class_fixedsize_stack">Class
<code>fixedsize_stack</code></link>
</bridgehead>
</para>
<para>
<emphasis role="bold">Boost.Fiber</emphasis> provides the class <link linkend="class_fixedsize_stack"><code>fixedsize_stack</code></link> which
models the <link linkend="stack_allocator_concept"><emphasis>stack-allocator
concept</emphasis></link>. In contrast to <link linkend="class_protected_fixedsize_stack"><code>protected_fixedsize_stack</code></link> it
does not append a guard page at the end of each stack. The memory is simply
managed by <code><phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase
role="identifier">malloc</phrase><phrase role="special">()</phrase></code>
and <code><phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase
role="identifier">free</phrase><phrase role="special">()</phrase></code>.
</para>
<programlisting><phrase role="preprocessor">#include</phrase> <phrase role="special">&lt;</phrase><phrase role="identifier">boost</phrase><phrase role="special">/</phrase><phrase role="identifier">context</phrase><phrase role="special">/</phrase><phrase role="identifier">fixedsize_stack</phrase><phrase role="special">.</phrase><phrase role="identifier">hpp</phrase><phrase role="special">&gt;</phrase>
<phrase role="keyword">namespace</phrase> <phrase role="identifier">boost</phrase> <phrase role="special">{</phrase>
<phrase role="keyword">namespace</phrase> <phrase role="identifier">fibers</phrase> <phrase role="special">{</phrase>
<phrase role="keyword">struct</phrase> <phrase role="identifier">fixedsize_stack</phrase> <phrase role="special">{</phrase>
<phrase role="identifier">fixedsize_stack</phrase><phrase role="special">(</phrase><phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">size_t</phrase> <phrase role="identifier">size</phrase> <phrase role="special">=</phrase> <phrase role="identifier">traits_type</phrase><phrase role="special">::</phrase><phrase role="identifier">default_size</phrase><phrase role="special">());</phrase>
<phrase role="identifier">stack_context</phrase> <phrase role="identifier">allocate</phrase><phrase role="special">();</phrase>
<phrase role="keyword">void</phrase> <phrase role="identifier">deallocate</phrase><phrase role="special">(</phrase> <phrase role="identifier">stack_context</phrase> <phrase role="special">&amp;);</phrase>
<phrase role="special">}</phrase>
<phrase role="special">}}</phrase>
</programlisting>
<para>
<bridgehead renderas="sect4" id="fixedsize_allocate_bridgehead">
<phrase id="fixedsize_allocate"/>
<link linkend="fixedsize_allocate">Member function
<code>allocate</code>()</link>
</bridgehead>
</para>
<programlisting><phrase role="identifier">stack_context</phrase> <phrase role="identifier">allocate</phrase><phrase role="special">();</phrase>
</programlisting>
<variablelist>
<title></title>
<varlistentry>
<term>Preconditions:</term>
<listitem>
<para>
<code><phrase role="identifier">traits_type</phrase><phrase role="special">::</phrase><phrase
role="identifier">minimum_size</phrase><phrase role="special">()</phrase>
<phrase role="special">&lt;=</phrase> <phrase role="identifier">size</phrase></code>
and <code><phrase role="identifier">traits_type</phrase><phrase role="special">::</phrase><phrase
role="identifier">is_unbounded</phrase><phrase role="special">()</phrase>
<phrase role="special">||</phrase> <phrase role="special">(</phrase>
<phrase role="identifier">traits_type</phrase><phrase role="special">::</phrase><phrase
role="identifier">maximum_size</phrase><phrase role="special">()</phrase>
<phrase role="special">&gt;=</phrase> <phrase role="identifier">size</phrase><phrase
role="special">)</phrase></code>.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>Effects:</term>
<listitem>
<para>
Allocates memory of at least <code><phrase role="identifier">size</phrase></code>
bytes and stores a pointer to the stack and its actual size in <code><phrase
role="identifier">sctx</phrase></code>. Depending on the architecture
(the stack grows downwards/upwards) the stored address is the highest/lowest
address of the stack.
</para>
</listitem>
</varlistentry>
</variablelist>
<para>
<bridgehead renderas="sect4" id="fixesize_deallocate_bridgehead">
<phrase id="fixesize_deallocate"/>
<link linkend="fixesize_deallocate">Member
function <code>deallocate</code>()</link>
</bridgehead>
</para>
<programlisting><phrase role="keyword">void</phrase> <phrase role="identifier">deallocate</phrase><phrase role="special">(</phrase> <phrase role="identifier">stack_context</phrase> <phrase role="special">&amp;</phrase> <phrase role="identifier">sctx</phrase><phrase role="special">);</phrase>
</programlisting>
<variablelist>
<title></title>
<varlistentry>
<term>Preconditions:</term>
<listitem>
<para>
<code><phrase role="identifier">sctx</phrase><phrase role="special">.</phrase><phrase
role="identifier">sp</phrase></code> is valid, <code><phrase role="identifier">traits_type</phrase><phrase
role="special">::</phrase><phrase role="identifier">minimum_size</phrase><phrase
role="special">()</phrase> <phrase role="special">&lt;=</phrase> <phrase
role="identifier">sctx</phrase><phrase role="special">.</phrase><phrase
role="identifier">size</phrase></code> and <code><phrase role="identifier">traits_type</phrase><phrase
role="special">::</phrase><phrase role="identifier">is_unbounded</phrase><phrase
role="special">()</phrase> <phrase role="special">||</phrase> <phrase
role="special">(</phrase> <phrase role="identifier">traits_type</phrase><phrase
role="special">::</phrase><phrase role="identifier">maximum_size</phrase><phrase
role="special">()</phrase> <phrase role="special">&gt;=</phrase> <phrase
role="identifier">sctx</phrase><phrase role="special">.</phrase><phrase
role="identifier">size</phrase><phrase role="special">)</phrase></code>.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>Effects:</term>
<listitem>
<para>
Deallocates the stack space.
</para>
</listitem>
</varlistentry>
</variablelist>
<para>
<anchor id="segmented"/><bridgehead renderas="sect4" id="class_segmented_stack_bridgehead">
<phrase id="class_segmented_stack"/>
<link linkend="class_segmented_stack">Class
<code>segmented_stack</code></link>
</bridgehead>
</para>
<para>
<emphasis role="bold">Boost.Fiber</emphasis> supports usage of a <link linkend="class_segmented_stack"><code>segmented_stack</code></link>,
i.e. the stack grows on demand. The fiber is created with a minimal stack size
which will be increased as required. Class <link linkend="class_segmented_stack"><code>segmented_stack</code></link> models
the <link linkend="stack_allocator_concept"><emphasis>stack-allocator concept</emphasis></link>.
In contrast to <link linkend="class_protected_fixedsize_stack"><code>protected_fixedsize_stack</code></link> and
<link linkend="class_fixedsize_stack"><code>fixedsize_stack</code></link> it creates a stack which grows on demand.
</para>
<note>
<para>
Segmented stacks are currently only supported by <emphasis role="bold">gcc</emphasis>
from version <emphasis role="bold">4.7</emphasis> and <emphasis role="bold">clang</emphasis>
from version <emphasis role="bold">3.4</emphasis> onwards. In order to use
a <link linkend="class_segmented_stack"><code>segmented_stack</code></link> <emphasis role="bold">Boost.Fiber</emphasis>
must be built with property <code><phrase role="identifier">segmented</phrase><phrase
role="special">-</phrase><phrase role="identifier">stacks</phrase></code>,
e.g. <emphasis role="bold">toolset=gcc segmented-stacks=on</emphasis> and
applying BOOST_USE_SEGMENTED_STACKS at b2/bjam command line.
</para>
</note>
<note>
<para>
Segmented stacks can only be used with callcc() using property <code><phrase
role="identifier">context</phrase><phrase role="special">-</phrase><phrase
role="identifier">impl</phrase><phrase role="special">=</phrase><phrase role="identifier">ucontext</phrase></code>.
</para>
</note>
<programlisting><phrase role="preprocessor">#include</phrase> <phrase role="special">&lt;</phrase><phrase role="identifier">boost</phrase><phrase role="special">/</phrase><phrase role="identifier">fiber</phrase><phrase role="special">/</phrase><phrase role="identifier">segmented_stack</phrase><phrase role="special">.</phrase><phrase role="identifier">hpp</phrase><phrase role="special">&gt;</phrase>
<phrase role="keyword">namespace</phrase> <phrase role="identifier">boost</phrase> <phrase role="special">{</phrase>
<phrase role="keyword">namespace</phrase> <phrase role="identifier">fibers</phrase> <phrase role="special">{</phrase>
<phrase role="keyword">struct</phrase> <phrase role="identifier">segmented_stack</phrase> <phrase role="special">{</phrase>
<phrase role="identifier">segmented_stack</phrase><phrase role="special">(</phrase><phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">size_t</phrase> <phrase role="identifier">stack_size</phrase> <phrase role="special">=</phrase> <phrase role="identifier">traits_type</phrase><phrase role="special">::</phrase><phrase role="identifier">default_size</phrase><phrase role="special">());</phrase>
<phrase role="identifier">stack_context</phrase> <phrase role="identifier">allocate</phrase><phrase role="special">();</phrase>
<phrase role="keyword">void</phrase> <phrase role="identifier">deallocate</phrase><phrase role="special">(</phrase> <phrase role="identifier">stack_context</phrase> <phrase role="special">&amp;);</phrase>
<phrase role="special">}</phrase>
<phrase role="special">}}</phrase>
</programlisting>
<para>
<bridgehead renderas="sect4" id="segmented_allocate_bridgehead">
<phrase id="segmented_allocate"/>
<link linkend="segmented_allocate">Member function
<code>allocate</code>()</link>
</bridgehead>
</para>
<programlisting><phrase role="identifier">stack_context</phrase> <phrase role="identifier">allocate</phrase><phrase role="special">();</phrase>
</programlisting>
<variablelist>
<title></title>
<varlistentry>
<term>Preconditions:</term>
<listitem>
<para>
<code><phrase role="identifier">traits_type</phrase><phrase role="special">::</phrase><phrase
role="identifier">minimum_size</phrase><phrase role="special">()</phrase>
<phrase role="special">&lt;=</phrase> <phrase role="identifier">size</phrase></code>
and <code><phrase role="identifier">traits_type</phrase><phrase role="special">::</phrase><phrase
role="identifier">is_unbounded</phrase><phrase role="special">()</phrase>
<phrase role="special">||</phrase> <phrase role="special">(</phrase>
<phrase role="identifier">traits_type</phrase><phrase role="special">::</phrase><phrase
role="identifier">maximum_size</phrase><phrase role="special">()</phrase>
<phrase role="special">&gt;=</phrase> <phrase role="identifier">size</phrase><phrase
role="special">)</phrase></code>.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>Effects:</term>
<listitem>
<para>
Allocates memory of at least <code><phrase role="identifier">size</phrase></code>
bytes and stores a pointer to the stack and its actual size in <code><phrase
role="identifier">sctx</phrase></code>. Depending on the architecture
(the stack grows downwards/upwards) the stored address is the highest/lowest
address of the stack.
</para>
</listitem>
</varlistentry>
</variablelist>
<para>
<bridgehead renderas="sect4" id="segmented_deallocate_bridgehead">
<phrase id="segmented_deallocate"/>
<link linkend="segmented_deallocate">Member
function <code>deallocate</code>()</link>
</bridgehead>
</para>
<programlisting><phrase role="keyword">void</phrase> <phrase role="identifier">deallocate</phrase><phrase role="special">(</phrase> <phrase role="identifier">stack_context</phrase> <phrase role="special">&amp;</phrase> <phrase role="identifier">sctx</phrase><phrase role="special">);</phrase>
</programlisting>
<variablelist>
<title></title>
<varlistentry>
<term>Preconditions:</term>
<listitem>
<para>
<code><phrase role="identifier">sctx</phrase><phrase role="special">.</phrase><phrase
role="identifier">sp</phrase></code> is valid, <code><phrase role="identifier">traits_type</phrase><phrase
role="special">::</phrase><phrase role="identifier">minimum_size</phrase><phrase
role="special">()</phrase> <phrase role="special">&lt;=</phrase> <phrase
role="identifier">sctx</phrase><phrase role="special">.</phrase><phrase
role="identifier">size</phrase></code> and <code><phrase role="identifier">traits_type</phrase><phrase
role="special">::</phrase><phrase role="identifier">is_unbounded</phrase><phrase
role="special">()</phrase> <phrase role="special">||</phrase> <phrase
role="special">(</phrase> <phrase role="identifier">traits_type</phrase><phrase
role="special">::</phrase><phrase role="identifier">maximum_size</phrase><phrase
role="special">()</phrase> <phrase role="special">&gt;=</phrase> <phrase
role="identifier">sctx</phrase><phrase role="special">.</phrase><phrase
role="identifier">size</phrase><phrase role="special">)</phrase></code>.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>Effects:</term>
<listitem>
<para>
Deallocates the stack space.
</para>
</listitem>
</varlistentry>
</variablelist>
<note>
<para>
If the library is compiled for segmented stacks, <link linkend="class_segmented_stack"><code>segmented_stack</code></link> is
the only available stack allocator.
</para>
</note>
<section id="fiber.stack.valgrind">
<title><link linkend="fiber.stack.valgrind">Support for valgrind</link></title>
<para>
Running programs that switch stacks under valgrind causes problems. Property
(b2 command-line) <code><phrase role="identifier">valgrind</phrase><phrase
role="special">=</phrase><phrase role="identifier">on</phrase></code> let
valgrind treat the memory regions as stack space which suppresses the errors.
</para>
</section>
</section>
<section id="fiber.synchronization">
<title><anchor id="synchronization"/><link linkend="fiber.synchronization">Synchronization</link></title>
<para>
In general, <emphasis role="bold">Boost.Fiber</emphasis> synchronization objects
can neither be moved nor copied. A synchronization object acts as a mutually-agreed
rendezvous point between different fibers. If such an object were copied somewhere
else, the new copy would have no consumers. If such an object were <emphasis>moved</emphasis>
somewhere else, leaving the original instance in an unspecified state, existing
consumers would behave strangely.
</para>
<para>
The fiber synchronization objects provided by this library will, by default,
safely synchronize fibers running on different threads. However, this level
of synchronization can be removed (for performance) by building the library
with <emphasis role="bold"><code><phrase role="identifier">BOOST_FIBERS_NO_ATOMICS</phrase></code></emphasis>
defined. When the library is built with that macro, you must ensure that all
the fibers referencing a particular synchronization object are running in the
same thread.
</para>
<section id="fiber.synchronization.mutex_types">
<title><link linkend="fiber.synchronization.mutex_types">Mutex Types</link></title>
<para>
<bridgehead renderas="sect4" id="class_mutex_bridgehead">
<phrase id="class_mutex"/>
<link linkend="class_mutex">Class <code>mutex</code></link>
</bridgehead>
</para>
<programlisting><phrase role="preprocessor">#include</phrase> <phrase role="special">&lt;</phrase><phrase role="identifier">boost</phrase><phrase role="special">/</phrase><phrase role="identifier">fiber</phrase><phrase role="special">/</phrase><phrase role="identifier">mutex</phrase><phrase role="special">.</phrase><phrase role="identifier">hpp</phrase><phrase role="special">&gt;</phrase>
<phrase role="keyword">namespace</phrase> <phrase role="identifier">boost</phrase> <phrase role="special">{</phrase>
<phrase role="keyword">namespace</phrase> <phrase role="identifier">fibers</phrase> <phrase role="special">{</phrase>
<phrase role="keyword">class</phrase> <phrase role="identifier">mutex</phrase> <phrase role="special">{</phrase>
<phrase role="keyword">public</phrase><phrase role="special">:</phrase>
<phrase role="identifier">mutex</phrase><phrase role="special">();</phrase>
<phrase role="special">~</phrase><phrase role="identifier">mutex</phrase><phrase role="special">();</phrase>
<phrase role="identifier">mutex</phrase><phrase role="special">(</phrase> <phrase role="identifier">mutex</phrase> <phrase role="keyword">const</phrase><phrase role="special">&amp;</phrase> <phrase role="identifier">other</phrase><phrase role="special">)</phrase> <phrase role="special">=</phrase> <phrase role="keyword">delete</phrase><phrase role="special">;</phrase>
<phrase role="identifier">mutex</phrase> <phrase role="special">&amp;</phrase> <phrase role="keyword">operator</phrase><phrase role="special">=(</phrase> <phrase role="identifier">mutex</phrase> <phrase role="keyword">const</phrase><phrase role="special">&amp;</phrase> <phrase role="identifier">other</phrase><phrase role="special">)</phrase> <phrase role="special">=</phrase> <phrase role="keyword">delete</phrase><phrase role="special">;</phrase>
<phrase role="keyword">void</phrase> <phrase role="identifier">lock</phrase><phrase role="special">();</phrase>
<phrase role="keyword">bool</phrase> <phrase role="identifier">try_lock</phrase><phrase role="special">();</phrase>
<phrase role="keyword">void</phrase> <phrase role="identifier">unlock</phrase><phrase role="special">();</phrase>
<phrase role="special">};</phrase>
<phrase role="special">}}</phrase>
</programlisting>
<para>
<link linkend="class_mutex"><code>mutex</code></link> provides an exclusive-ownership mutex. At most one fiber
can own the lock on a given instance of <link linkend="class_mutex"><code>mutex</code></link> at any time. Multiple
concurrent calls to <code><phrase role="identifier">lock</phrase><phrase
role="special">()</phrase></code>, <code><phrase role="identifier">try_lock</phrase><phrase
role="special">()</phrase></code> and <code><phrase role="identifier">unlock</phrase><phrase
role="special">()</phrase></code> shall be permitted.
</para>
<para>
Any fiber blocked in <code><phrase role="identifier">lock</phrase><phrase
role="special">()</phrase></code> is suspended until the owning fiber releases
the lock by calling <code><phrase role="identifier">unlock</phrase><phrase
role="special">()</phrase></code>.
</para>
<para>
<bridgehead renderas="sect4" id="mutex_lock_bridgehead">
<phrase id="mutex_lock"/>
<link linkend="mutex_lock">Member function <code>lock</code>()</link>
</bridgehead>
</para>
<programlisting><phrase role="keyword">void</phrase> <phrase role="identifier">lock</phrase><phrase role="special">();</phrase>
</programlisting>
<variablelist>
<title></title>
<varlistentry>
<term>Precondition:</term>
<listitem>
<para>
The calling fiber doesn't own the mutex.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>Effects:</term>
<listitem>
<para>
The current fiber blocks until ownership can be obtained.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>Throws:</term>
<listitem>
<para>
<code><phrase role="identifier">lock_error</phrase></code>
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>Error Conditions:</term>
<listitem>
<para>
<emphasis role="bold">resource_deadlock_would_occur</emphasis>: if
<code><phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase
role="identifier">this_fiber</phrase><phrase role="special">::</phrase><phrase
role="identifier">get_id</phrase><phrase role="special">()</phrase></code>
already owns the mutex.
</para>
</listitem>
</varlistentry>
</variablelist>
<para>
<bridgehead renderas="sect4" id="mutex_try_lock_bridgehead">
<phrase id="mutex_try_lock"/>
<link linkend="mutex_try_lock">Member function <code>try_lock</code>()</link>
</bridgehead>
</para>
<programlisting><phrase role="keyword">bool</phrase> <phrase role="identifier">try_lock</phrase><phrase role="special">();</phrase>
</programlisting>
<variablelist>
<title></title>
<varlistentry>
<term>Precondition:</term>
<listitem>
<para>
The calling fiber doesn't own the mutex.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>Effects:</term>
<listitem>
<para>
Attempt to obtain ownership for the current fiber without blocking.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>Returns:</term>
<listitem>
<para>
<code><phrase role="keyword">true</phrase></code> if ownership was
obtained for the current fiber, <code><phrase role="keyword">false</phrase></code>
otherwise.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>Throws:</term>
<listitem>
<para>
<code><phrase role="identifier">lock_error</phrase></code>
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>Error Conditions:</term>
<listitem>
<para>
<emphasis role="bold">resource_deadlock_would_occur</emphasis>: if
<code><phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase
role="identifier">this_fiber</phrase><phrase role="special">::</phrase><phrase
role="identifier">get_id</phrase><phrase role="special">()</phrase></code>
already owns the mutex.
</para>
</listitem>
</varlistentry>
</variablelist>
<para>
<bridgehead renderas="sect4" id="mutex_unlock_bridgehead">
<phrase id="mutex_unlock"/>
<link linkend="mutex_unlock">Member function <code>unlock</code>()</link>
</bridgehead>
</para>
<programlisting><phrase role="keyword">void</phrase> <phrase role="identifier">unlock</phrase><phrase role="special">();</phrase>
</programlisting>
<variablelist>
<title></title>
<varlistentry>
<term>Precondition:</term>
<listitem>
<para>
The current fiber owns <code><phrase role="special">*</phrase><phrase
role="keyword">this</phrase></code>.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>Effects:</term>
<listitem>
<para>
Releases a lock on <code><phrase role="special">*</phrase><phrase role="keyword">this</phrase></code>
by the current fiber.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>Throws:</term>
<listitem>
<para>
<code><phrase role="identifier">lock_error</phrase></code>
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>Error Conditions:</term>
<listitem>
<para>
<emphasis role="bold">operation_not_permitted</emphasis>: if <code><phrase
role="identifier">boost</phrase><phrase role="special">::</phrase><phrase
role="identifier">this_fiber</phrase><phrase role="special">::</phrase><phrase
role="identifier">get_id</phrase><phrase role="special">()</phrase></code>
does not own the mutex.
</para>
</listitem>
</varlistentry>
</variablelist>
<para>
<bridgehead renderas="sect4" id="class_timed_mutex_bridgehead">
<phrase id="class_timed_mutex"/>
<link linkend="class_timed_mutex">Class <code>timed_mutex</code></link>
</bridgehead>
</para>
<programlisting><phrase role="preprocessor">#include</phrase> <phrase role="special">&lt;</phrase><phrase role="identifier">boost</phrase><phrase role="special">/</phrase><phrase role="identifier">fiber</phrase><phrase role="special">/</phrase><phrase role="identifier">timed_mutex</phrase><phrase role="special">.</phrase><phrase role="identifier">hpp</phrase><phrase role="special">&gt;</phrase>
<phrase role="keyword">namespace</phrase> <phrase role="identifier">boost</phrase> <phrase role="special">{</phrase>
<phrase role="keyword">namespace</phrase> <phrase role="identifier">fibers</phrase> <phrase role="special">{</phrase>
<phrase role="keyword">class</phrase> <phrase role="identifier">timed_mutex</phrase> <phrase role="special">{</phrase>
<phrase role="keyword">public</phrase><phrase role="special">:</phrase>
<phrase role="identifier">timed_mutex</phrase><phrase role="special">();</phrase>
<phrase role="special">~</phrase><phrase role="identifier">timed_mutex</phrase><phrase role="special">();</phrase>
<phrase role="identifier">timed_mutex</phrase><phrase role="special">(</phrase> <phrase role="identifier">timed_mutex</phrase> <phrase role="keyword">const</phrase><phrase role="special">&amp;</phrase> <phrase role="identifier">other</phrase><phrase role="special">)</phrase> <phrase role="special">=</phrase> <phrase role="keyword">delete</phrase><phrase role="special">;</phrase>
<phrase role="identifier">timed_mutex</phrase> <phrase role="special">&amp;</phrase> <phrase role="keyword">operator</phrase><phrase role="special">=(</phrase> <phrase role="identifier">timed_mutex</phrase> <phrase role="keyword">const</phrase><phrase role="special">&amp;</phrase> <phrase role="identifier">other</phrase><phrase role="special">)</phrase> <phrase role="special">=</phrase> <phrase role="keyword">delete</phrase><phrase role="special">;</phrase>
<phrase role="keyword">void</phrase> <phrase role="identifier">lock</phrase><phrase role="special">();</phrase>
<phrase role="keyword">bool</phrase> <phrase role="identifier">try_lock</phrase><phrase role="special">();</phrase>
<phrase role="keyword">void</phrase> <phrase role="identifier">unlock</phrase><phrase role="special">();</phrase>
<phrase role="keyword">template</phrase><phrase role="special">&lt;</phrase> <phrase role="keyword">typename</phrase> <phrase role="identifier">Clock</phrase><phrase role="special">,</phrase> <phrase role="keyword">typename</phrase> <phrase role="identifier">Duration</phrase> <phrase role="special">&gt;</phrase>
<phrase role="keyword">bool</phrase> <phrase role="identifier">try_lock_until</phrase><phrase role="special">(</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">chrono</phrase><phrase role="special">::</phrase><phrase role="identifier">time_point</phrase><phrase role="special">&lt;</phrase> <phrase role="identifier">Clock</phrase><phrase role="special">,</phrase> <phrase role="identifier">Duration</phrase> <phrase role="special">&gt;</phrase> <phrase role="keyword">const</phrase><phrase role="special">&amp;</phrase> <phrase role="identifier">timeout_time</phrase><phrase role="special">);</phrase>
<phrase role="keyword">template</phrase><phrase role="special">&lt;</phrase> <phrase role="keyword">typename</phrase> <phrase role="identifier">Rep</phrase><phrase role="special">,</phrase> <phrase role="keyword">typename</phrase> <phrase role="identifier">Period</phrase> <phrase role="special">&gt;</phrase>
<phrase role="keyword">bool</phrase> <phrase role="identifier">try_lock_for</phrase><phrase role="special">(</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">chrono</phrase><phrase role="special">::</phrase><phrase role="identifier">duration</phrase><phrase role="special">&lt;</phrase> <phrase role="identifier">Rep</phrase><phrase role="special">,</phrase> <phrase role="identifier">Period</phrase> <phrase role="special">&gt;</phrase> <phrase role="keyword">const</phrase><phrase role="special">&amp;</phrase> <phrase role="identifier">timeout_duration</phrase><phrase role="special">);</phrase>
<phrase role="special">};</phrase>
<phrase role="special">}}</phrase>
</programlisting>
<para>
<link linkend="class_timed_mutex"><code>timed_mutex</code></link> provides an exclusive-ownership mutex. At most
one fiber can own the lock on a given instance of <link linkend="class_timed_mutex"><code>timed_mutex</code></link> at
any time. Multiple concurrent calls to <code><phrase role="identifier">lock</phrase><phrase
role="special">()</phrase></code>, <code><phrase role="identifier">try_lock</phrase><phrase
role="special">()</phrase></code>, <code><phrase role="identifier">try_lock_until</phrase><phrase
role="special">()</phrase></code>, <code><phrase role="identifier">try_lock_for</phrase><phrase
role="special">()</phrase></code> and <code><phrase role="identifier">unlock</phrase><phrase
role="special">()</phrase></code> shall be permitted.
</para>
<para>
<bridgehead renderas="sect4" id="timed_mutex_lock_bridgehead">
<phrase id="timed_mutex_lock"/>
<link linkend="timed_mutex_lock">Member function
<code>lock</code>()</link>
</bridgehead>
</para>
<programlisting><phrase role="keyword">void</phrase> <phrase role="identifier">lock</phrase><phrase role="special">();</phrase>
</programlisting>
<variablelist>
<title></title>
<varlistentry>
<term>Precondition:</term>
<listitem>
<para>
The calling fiber doesn't own the mutex.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>Effects:</term>
<listitem>
<para>
The current fiber blocks until ownership can be obtained.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>Throws:</term>
<listitem>
<para>
<code><phrase role="identifier">lock_error</phrase></code>
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>Error Conditions:</term>
<listitem>
<para>
<emphasis role="bold">resource_deadlock_would_occur</emphasis>: if
<code><phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase
role="identifier">this_fiber</phrase><phrase role="special">::</phrase><phrase
role="identifier">get_id</phrase><phrase role="special">()</phrase></code>
already owns the mutex.
</para>
</listitem>
</varlistentry>
</variablelist>
<para>
<bridgehead renderas="sect4" id="timed_mutex_try_lock_bridgehead">
<phrase id="timed_mutex_try_lock"/>
<link linkend="timed_mutex_try_lock">Member
function <code>try_lock</code>()</link>
</bridgehead>
</para>
<programlisting><phrase role="keyword">bool</phrase> <phrase role="identifier">try_lock</phrase><phrase role="special">();</phrase>
</programlisting>
<variablelist>
<title></title>
<varlistentry>
<term>Precondition:</term>
<listitem>
<para>
The calling fiber doesn't own the mutex.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>Effects:</term>
<listitem>
<para>
Attempt to obtain ownership for the current fiber without blocking.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>Returns:</term>
<listitem>
<para>
<code><phrase role="keyword">true</phrase></code> if ownership was
obtained for the current fiber, <code><phrase role="keyword">false</phrase></code>
otherwise.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>Throws:</term>
<listitem>
<para>
<code><phrase role="identifier">lock_error</phrase></code>
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>Error Conditions:</term>
<listitem>
<para>
<emphasis role="bold">resource_deadlock_would_occur</emphasis>: if
<code><phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase
role="identifier">this_fiber</phrase><phrase role="special">::</phrase><phrase
role="identifier">get_id</phrase><phrase role="special">()</phrase></code>
already owns the mutex.
</para>
</listitem>
</varlistentry>
</variablelist>
<para>
<bridgehead renderas="sect4" id="timed_mutex_unlock_bridgehead">
<phrase id="timed_mutex_unlock"/>
<link linkend="timed_mutex_unlock">Member function
<code>unlock</code>()</link>
</bridgehead>
</para>
<programlisting><phrase role="keyword">void</phrase> <phrase role="identifier">unlock</phrase><phrase role="special">();</phrase>
</programlisting>
<variablelist>
<title></title>
<varlistentry>
<term>Precondition:</term>
<listitem>
<para>
The current fiber owns <code><phrase role="special">*</phrase><phrase
role="keyword">this</phrase></code>.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>Effects:</term>
<listitem>
<para>
Releases a lock on <code><phrase role="special">*</phrase><phrase role="keyword">this</phrase></code>
by the current fiber.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>Throws:</term>
<listitem>
<para>
<code><phrase role="identifier">lock_error</phrase></code>
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>Error Conditions:</term>
<listitem>
<para>
<emphasis role="bold">operation_not_permitted</emphasis>: if <code><phrase
role="identifier">boost</phrase><phrase role="special">::</phrase><phrase
role="identifier">this_fiber</phrase><phrase role="special">::</phrase><phrase
role="identifier">get_id</phrase><phrase role="special">()</phrase></code>
does not own the mutex.
</para>
</listitem>
</varlistentry>
</variablelist>
<para>
<bridgehead renderas="sect4" id="timed_mutex_try_lock_until_bridgehead">
<phrase id="timed_mutex_try_lock_until"/>
<link linkend="timed_mutex_try_lock_until">Templated
member function <code>try_lock_until</code>()</link>
</bridgehead>
</para>
<programlisting><phrase role="keyword">template</phrase><phrase role="special">&lt;</phrase> <phrase role="keyword">typename</phrase> <phrase role="identifier">Clock</phrase><phrase role="special">,</phrase> <phrase role="keyword">typename</phrase> <phrase role="identifier">Duration</phrase> <phrase role="special">&gt;</phrase>
<phrase role="keyword">bool</phrase> <phrase role="identifier">try_lock_until</phrase><phrase role="special">(</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">chrono</phrase><phrase role="special">::</phrase><phrase role="identifier">time_point</phrase><phrase role="special">&lt;</phrase> <phrase role="identifier">Clock</phrase><phrase role="special">,</phrase> <phrase role="identifier">Duration</phrase> <phrase role="special">&gt;</phrase> <phrase role="keyword">const</phrase><phrase role="special">&amp;</phrase> <phrase role="identifier">timeout_time</phrase><phrase role="special">);</phrase>
</programlisting>
<variablelist>
<title></title>
<varlistentry>
<term>Precondition:</term>
<listitem>
<para>
The calling fiber doesn't own the mutex.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>Effects:</term>
<listitem>
<para>
Attempt to obtain ownership for the current fiber. Blocks until ownership
can be obtained, or the specified time is reached. If the specified
time has already passed, behaves as <link linkend="timed_mutex_try_lock"><code>timed_mutex::try_lock()</code></link>.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>Returns:</term>
<listitem>
<para>
<code><phrase role="keyword">true</phrase></code> if ownership was
obtained for the current fiber, <code><phrase role="keyword">false</phrase></code>
otherwise.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>Throws:</term>
<listitem>
<para>
<code><phrase role="identifier">lock_error</phrase></code>, timeout-related
exceptions.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>Error Conditions:</term>
<listitem>
<para>
<emphasis role="bold">resource_deadlock_would_occur</emphasis>: if
<code><phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase
role="identifier">this_fiber</phrase><phrase role="special">::</phrase><phrase
role="identifier">get_id</phrase><phrase role="special">()</phrase></code>
already owns the mutex.
</para>
</listitem>
</varlistentry>
</variablelist>
<para>
<bridgehead renderas="sect4" id="timed_mutex_try_lock_for_bridgehead">
<phrase id="timed_mutex_try_lock_for"/>
<link linkend="timed_mutex_try_lock_for">Templated
member function <code>try_lock_for</code>()</link>
</bridgehead>
</para>
<programlisting><phrase role="keyword">template</phrase><phrase role="special">&lt;</phrase> <phrase role="keyword">typename</phrase> <phrase role="identifier">Rep</phrase><phrase role="special">,</phrase> <phrase role="keyword">typename</phrase> <phrase role="identifier">Period</phrase> <phrase role="special">&gt;</phrase>
<phrase role="keyword">bool</phrase> <phrase role="identifier">try_lock_for</phrase><phrase role="special">(</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">chrono</phrase><phrase role="special">::</phrase><phrase role="identifier">duration</phrase><phrase role="special">&lt;</phrase> <phrase role="identifier">Rep</phrase><phrase role="special">,</phrase> <phrase role="identifier">Period</phrase> <phrase role="special">&gt;</phrase> <phrase role="keyword">const</phrase><phrase role="special">&amp;</phrase> <phrase role="identifier">timeout_duration</phrase><phrase role="special">);</phrase>
</programlisting>
<variablelist>
<title></title>
<varlistentry>
<term>Precondition:</term>
<listitem>
<para>
The calling fiber doesn't own the mutex.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>Effects:</term>
<listitem>
<para>
Attempt to obtain ownership for the current fiber. Blocks until ownership
can be obtained, or the specified time is reached. If the specified
time has already passed, behaves as <link linkend="timed_mutex_try_lock"><code>timed_mutex::try_lock()</code></link>.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>Returns:</term>
<listitem>
<para>
<code><phrase role="keyword">true</phrase></code> if ownership was
obtained for the current fiber, <code><phrase role="keyword">false</phrase></code>
otherwise.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>Throws:</term>
<listitem>
<para>
<code><phrase role="identifier">lock_error</phrase></code>, timeout-related
exceptions.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>Error Conditions:</term>
<listitem>
<para>
<emphasis role="bold">resource_deadlock_would_occur</emphasis>: if
<code><phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase
role="identifier">this_fiber</phrase><phrase role="special">::</phrase><phrase
role="identifier">get_id</phrase><phrase role="special">()</phrase></code>
already owns the mutex.
</para>
</listitem>
</varlistentry>
</variablelist>
<para>
<bridgehead renderas="sect4" id="class_recursive_mutex_bridgehead">
<phrase id="class_recursive_mutex"/>
<link linkend="class_recursive_mutex">Class
<code>recursive_mutex</code></link>
</bridgehead>
</para>
<programlisting><phrase role="preprocessor">#include</phrase> <phrase role="special">&lt;</phrase><phrase role="identifier">boost</phrase><phrase role="special">/</phrase><phrase role="identifier">fiber</phrase><phrase role="special">/</phrase><phrase role="identifier">recursive_mutex</phrase><phrase role="special">.</phrase><phrase role="identifier">hpp</phrase><phrase role="special">&gt;</phrase>
<phrase role="keyword">namespace</phrase> <phrase role="identifier">boost</phrase> <phrase role="special">{</phrase>
<phrase role="keyword">namespace</phrase> <phrase role="identifier">fibers</phrase> <phrase role="special">{</phrase>
<phrase role="keyword">class</phrase> <phrase role="identifier">recursive_mutex</phrase> <phrase role="special">{</phrase>
<phrase role="keyword">public</phrase><phrase role="special">:</phrase>
<phrase role="identifier">recursive_mutex</phrase><phrase role="special">();</phrase>
<phrase role="special">~</phrase><phrase role="identifier">recursive_mutex</phrase><phrase role="special">();</phrase>
<phrase role="identifier">recursive_mutex</phrase><phrase role="special">(</phrase> <phrase role="identifier">recursive_mutex</phrase> <phrase role="keyword">const</phrase><phrase role="special">&amp;</phrase> <phrase role="identifier">other</phrase><phrase role="special">)</phrase> <phrase role="special">=</phrase> <phrase role="keyword">delete</phrase><phrase role="special">;</phrase>
<phrase role="identifier">recursive_mutex</phrase> <phrase role="special">&amp;</phrase> <phrase role="keyword">operator</phrase><phrase role="special">=(</phrase> <phrase role="identifier">recursive_mutex</phrase> <phrase role="keyword">const</phrase><phrase role="special">&amp;</phrase> <phrase role="identifier">other</phrase><phrase role="special">)</phrase> <phrase role="special">=</phrase> <phrase role="keyword">delete</phrase><phrase role="special">;</phrase>
<phrase role="keyword">void</phrase> <phrase role="identifier">lock</phrase><phrase role="special">();</phrase>
<phrase role="keyword">bool</phrase> <phrase role="identifier">try_lock</phrase><phrase role="special">()</phrase> <phrase role="keyword">noexcept</phrase><phrase role="special">;</phrase>
<phrase role="keyword">void</phrase> <phrase role="identifier">unlock</phrase><phrase role="special">();</phrase>
<phrase role="special">};</phrase>
<phrase role="special">}}</phrase>
</programlisting>
<para>
<link linkend="class_recursive_mutex"><code>recursive_mutex</code></link> provides an exclusive-ownership recursive
mutex. At most one fiber can own the lock on a given instance of <link linkend="class_recursive_mutex"><code>recursive_mutex</code></link> at
any time. Multiple concurrent calls to <code><phrase role="identifier">lock</phrase><phrase
role="special">()</phrase></code>, <code><phrase role="identifier">try_lock</phrase><phrase
role="special">()</phrase></code> and <code><phrase role="identifier">unlock</phrase><phrase
role="special">()</phrase></code> shall be permitted. A fiber that already
has exclusive ownership of a given <link linkend="class_recursive_mutex"><code>recursive_mutex</code></link> instance
can call <code><phrase role="identifier">lock</phrase><phrase role="special">()</phrase></code>
or <code><phrase role="identifier">try_lock</phrase><phrase role="special">()</phrase></code>
to acquire an additional level of ownership of the mutex. <code><phrase role="identifier">unlock</phrase><phrase
role="special">()</phrase></code> must be called once for each level of ownership
acquired by a single fiber before ownership can be acquired by another fiber.
</para>
<para>
<bridgehead renderas="sect4" id="recursive_mutex_lock_bridgehead">
<phrase id="recursive_mutex_lock"/>
<link linkend="recursive_mutex_lock">Member
function <code>lock</code>()</link>
</bridgehead>
</para>
<programlisting><phrase role="keyword">void</phrase> <phrase role="identifier">lock</phrase><phrase role="special">();</phrase>
</programlisting>
<variablelist>
<title></title>
<varlistentry>
<term>Effects:</term>
<listitem>
<para>
The current fiber blocks until ownership can be obtained.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>Throws:</term>
<listitem>
<para>
Nothing
</para>
</listitem>
</varlistentry>
</variablelist>
<para>
<bridgehead renderas="sect4" id="recursive_mutex_try_lock_bridgehead">
<phrase id="recursive_mutex_try_lock"/>
<link linkend="recursive_mutex_try_lock">Member
function <code>try_lock</code>()</link>
</bridgehead>
</para>
<programlisting><phrase role="keyword">bool</phrase> <phrase role="identifier">try_lock</phrase><phrase role="special">()</phrase> <phrase role="keyword">noexcept</phrase><phrase role="special">;</phrase>
</programlisting>
<variablelist>
<title></title>
<varlistentry>
<term>Effects:</term>
<listitem>
<para>
Attempt to obtain ownership for the current fiber without blocking.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>Returns:</term>
<listitem>
<para>
<code><phrase role="keyword">true</phrase></code> if ownership was
obtained for the current fiber, <code><phrase role="keyword">false</phrase></code>
otherwise.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>Throws:</term>
<listitem>
<para>
Nothing.
</para>
</listitem>
</varlistentry>
</variablelist>
<para>
<bridgehead renderas="sect4" id="recursive_mutex_unlock_bridgehead">
<phrase id="recursive_mutex_unlock"/>
<link linkend="recursive_mutex_unlock">Member
function <code>unlock</code>()</link>
</bridgehead>
</para>
<programlisting><phrase role="keyword">void</phrase> <phrase role="identifier">unlock</phrase><phrase role="special">();</phrase>
</programlisting>
<variablelist>
<title></title>
<varlistentry>
<term>Effects:</term>
<listitem>
<para>
Releases a lock on <code><phrase role="special">*</phrase><phrase role="keyword">this</phrase></code>
by the current fiber.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>Throws:</term>
<listitem>
<para>
<code><phrase role="identifier">lock_error</phrase></code>
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>Error Conditions:</term>
<listitem>
<para>
<emphasis role="bold">operation_not_permitted</emphasis>: if <code><phrase
role="identifier">boost</phrase><phrase role="special">::</phrase><phrase
role="identifier">this_fiber</phrase><phrase role="special">::</phrase><phrase
role="identifier">get_id</phrase><phrase role="special">()</phrase></code>
does not own the mutex.
</para>
</listitem>
</varlistentry>
</variablelist>
<para>
<bridgehead renderas="sect4" id="class_recursive_timed_mutex_bridgehead">
<phrase id="class_recursive_timed_mutex"/>
<link linkend="class_recursive_timed_mutex">Class
<code>recursive_timed_mutex</code></link>
</bridgehead>
</para>
<programlisting><phrase role="preprocessor">#include</phrase> <phrase role="special">&lt;</phrase><phrase role="identifier">boost</phrase><phrase role="special">/</phrase><phrase role="identifier">fiber</phrase><phrase role="special">/</phrase><phrase role="identifier">recursive_timed_mutex</phrase><phrase role="special">.</phrase><phrase role="identifier">hpp</phrase><phrase role="special">&gt;</phrase>
<phrase role="keyword">namespace</phrase> <phrase role="identifier">boost</phrase> <phrase role="special">{</phrase>
<phrase role="keyword">namespace</phrase> <phrase role="identifier">fibers</phrase> <phrase role="special">{</phrase>
<phrase role="keyword">class</phrase> <phrase role="identifier">recursive_timed_mutex</phrase> <phrase role="special">{</phrase>
<phrase role="keyword">public</phrase><phrase role="special">:</phrase>
<phrase role="identifier">recursive_timed_mutex</phrase><phrase role="special">();</phrase>
<phrase role="special">~</phrase><phrase role="identifier">recursive_timed_mutex</phrase><phrase role="special">();</phrase>
<phrase role="identifier">recursive_timed_mutex</phrase><phrase role="special">(</phrase> <phrase role="identifier">recursive_timed_mutex</phrase> <phrase role="keyword">const</phrase><phrase role="special">&amp;</phrase> <phrase role="identifier">other</phrase><phrase role="special">)</phrase> <phrase role="special">=</phrase> <phrase role="keyword">delete</phrase><phrase role="special">;</phrase>
<phrase role="identifier">recursive_timed_mutex</phrase> <phrase role="special">&amp;</phrase> <phrase role="keyword">operator</phrase><phrase role="special">=(</phrase> <phrase role="identifier">recursive_timed_mutex</phrase> <phrase role="keyword">const</phrase><phrase role="special">&amp;</phrase> <phrase role="identifier">other</phrase><phrase role="special">)</phrase> <phrase role="special">=</phrase> <phrase role="keyword">delete</phrase><phrase role="special">;</phrase>
<phrase role="keyword">void</phrase> <phrase role="identifier">lock</phrase><phrase role="special">();</phrase>
<phrase role="keyword">bool</phrase> <phrase role="identifier">try_lock</phrase><phrase role="special">()</phrase> <phrase role="keyword">noexcept</phrase><phrase role="special">;</phrase>
<phrase role="keyword">void</phrase> <phrase role="identifier">unlock</phrase><phrase role="special">();</phrase>
<phrase role="keyword">template</phrase><phrase role="special">&lt;</phrase> <phrase role="keyword">typename</phrase> <phrase role="identifier">Clock</phrase><phrase role="special">,</phrase> <phrase role="keyword">typename</phrase> <phrase role="identifier">Duration</phrase> <phrase role="special">&gt;</phrase>
<phrase role="keyword">bool</phrase> <phrase role="identifier">try_lock_until</phrase><phrase role="special">(</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">chrono</phrase><phrase role="special">::</phrase><phrase role="identifier">time_point</phrase><phrase role="special">&lt;</phrase> <phrase role="identifier">Clock</phrase><phrase role="special">,</phrase> <phrase role="identifier">Duration</phrase> <phrase role="special">&gt;</phrase> <phrase role="keyword">const</phrase><phrase role="special">&amp;</phrase> <phrase role="identifier">timeout_time</phrase><phrase role="special">);</phrase>
<phrase role="keyword">template</phrase><phrase role="special">&lt;</phrase> <phrase role="keyword">typename</phrase> <phrase role="identifier">Rep</phrase><phrase role="special">,</phrase> <phrase role="keyword">typename</phrase> <phrase role="identifier">Period</phrase> <phrase role="special">&gt;</phrase>
<phrase role="keyword">bool</phrase> <phrase role="identifier">try_lock_for</phrase><phrase role="special">(</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">chrono</phrase><phrase role="special">::</phrase><phrase role="identifier">duration</phrase><phrase role="special">&lt;</phrase> <phrase role="identifier">Rep</phrase><phrase role="special">,</phrase> <phrase role="identifier">Period</phrase> <phrase role="special">&gt;</phrase> <phrase role="keyword">const</phrase><phrase role="special">&amp;</phrase> <phrase role="identifier">timeout_duration</phrase><phrase role="special">);</phrase>
<phrase role="special">};</phrase>
<phrase role="special">}}</phrase>
</programlisting>
<para>
<link linkend="class_recursive_timed_mutex"><code>recursive_timed_mutex</code></link> provides an exclusive-ownership
recursive mutex. At most one fiber can own the lock on a given instance of
<link linkend="class_recursive_timed_mutex"><code>recursive_timed_mutex</code></link> at any time. Multiple concurrent
calls to <code><phrase role="identifier">lock</phrase><phrase role="special">()</phrase></code>,
<code><phrase role="identifier">try_lock</phrase><phrase role="special">()</phrase></code>,
<code><phrase role="identifier">try_lock_for</phrase><phrase role="special">()</phrase></code>,
<code><phrase role="identifier">try_lock_until</phrase><phrase role="special">()</phrase></code>
and <code><phrase role="identifier">unlock</phrase><phrase role="special">()</phrase></code>
shall be permitted. A fiber that already has exclusive ownership of a given
<link linkend="class_recursive_timed_mutex"><code>recursive_timed_mutex</code></link> instance can call <code><phrase
role="identifier">lock</phrase><phrase role="special">()</phrase></code>,
<code><phrase role="identifier">try_lock</phrase><phrase role="special">()</phrase></code>,
<code><phrase role="identifier">try_lock_for</phrase><phrase role="special">()</phrase></code>
or <code><phrase role="identifier">try_lock_until</phrase><phrase role="special">()</phrase></code>
to acquire an additional level of ownership of the mutex. <code><phrase role="identifier">unlock</phrase><phrase
role="special">()</phrase></code> must be called once for each level of ownership
acquired by a single fiber before ownership can be acquired by another fiber.
</para>
<para>
<bridgehead renderas="sect4" id="recursive_timed_mutex_lock_bridgehead">
<phrase id="recursive_timed_mutex_lock"/>
<link linkend="recursive_timed_mutex_lock">Member
function <code>lock</code>()</link>
</bridgehead>
</para>
<programlisting><phrase role="keyword">void</phrase> <phrase role="identifier">lock</phrase><phrase role="special">();</phrase>
</programlisting>
<variablelist>
<title></title>
<varlistentry>
<term>Effects:</term>
<listitem>
<para>
The current fiber blocks until ownership can be obtained.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>Throws:</term>
<listitem>
<para>
Nothing
</para>
</listitem>
</varlistentry>
</variablelist>
<para>
<bridgehead renderas="sect4" id="recursive_timed_mutex_try_lock_bridgehead">
<phrase id="recursive_timed_mutex_try_lock"/>
<link linkend="recursive_timed_mutex_try_lock">Member
function <code>try_lock</code>()</link>
</bridgehead>
</para>
<programlisting><phrase role="keyword">bool</phrase> <phrase role="identifier">try_lock</phrase><phrase role="special">()</phrase> <phrase role="keyword">noexcept</phrase><phrase role="special">;</phrase>
</programlisting>
<variablelist>
<title></title>
<varlistentry>
<term>Effects:</term>
<listitem>
<para>
Attempt to obtain ownership for the current fiber without blocking.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>Returns:</term>
<listitem>
<para>
<code><phrase role="keyword">true</phrase></code> if ownership was
obtained for the current fiber, <code><phrase role="keyword">false</phrase></code>
otherwise.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>Throws:</term>
<listitem>
<para>
Nothing.
</para>
</listitem>
</varlistentry>
</variablelist>
<para>
<bridgehead renderas="sect4" id="recursive_timed_mutex_unlock_bridgehead">
<phrase id="recursive_timed_mutex_unlock"/>
<link linkend="recursive_timed_mutex_unlock">Member
function <code>unlock</code>()</link>
</bridgehead>
</para>
<programlisting><phrase role="keyword">void</phrase> <phrase role="identifier">unlock</phrase><phrase role="special">();</phrase>
</programlisting>
<variablelist>
<title></title>
<varlistentry>
<term>Effects:</term>
<listitem>
<para>
Releases a lock on <code><phrase role="special">*</phrase><phrase role="keyword">this</phrase></code>
by the current fiber.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>Throws:</term>
<listitem>
<para>
<code><phrase role="identifier">lock_error</phrase></code>
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>Error Conditions:</term>
<listitem>
<para>
<emphasis role="bold">operation_not_permitted</emphasis>: if <code><phrase
role="identifier">boost</phrase><phrase role="special">::</phrase><phrase
role="identifier">this_fiber</phrase><phrase role="special">::</phrase><phrase
role="identifier">get_id</phrase><phrase role="special">()</phrase></code>
does not own the mutex.
</para>
</listitem>
</varlistentry>
</variablelist>
<para>
<bridgehead renderas="sect4" id="recursive_timed_mutex_try_lock_until_bridgehead">
<phrase id="recursive_timed_mutex_try_lock_until"/>
<link linkend="recursive_timed_mutex_try_lock_until">Templated
member function <code>try_lock_until</code>()</link>
</bridgehead>
</para>
<programlisting><phrase role="keyword">template</phrase><phrase role="special">&lt;</phrase> <phrase role="keyword">typename</phrase> <phrase role="identifier">Clock</phrase><phrase role="special">,</phrase> <phrase role="keyword">typename</phrase> <phrase role="identifier">Duration</phrase> <phrase role="special">&gt;</phrase>
<phrase role="keyword">bool</phrase> <phrase role="identifier">try_lock_until</phrase><phrase role="special">(</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">chrono</phrase><phrase role="special">::</phrase><phrase role="identifier">time_point</phrase><phrase role="special">&lt;</phrase> <phrase role="identifier">Clock</phrase><phrase role="special">,</phrase> <phrase role="identifier">Duration</phrase> <phrase role="special">&gt;</phrase> <phrase role="keyword">const</phrase><phrase role="special">&amp;</phrase> <phrase role="identifier">timeout_time</phrase><phrase role="special">);</phrase>
</programlisting>
<variablelist>
<title></title>
<varlistentry>
<term>Effects:</term>
<listitem>
<para>
Attempt to obtain ownership for the current fiber. Blocks until ownership
can be obtained, or the specified time is reached. If the specified
time has already passed, behaves as <link linkend="recursive_timed_mutex_try_lock"><code>recursive_timed_mutex::try_lock()</code></link>.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>Returns:</term>
<listitem>
<para>
<code><phrase role="keyword">true</phrase></code> if ownership was
obtained for the current fiber, <code><phrase role="keyword">false</phrase></code>
otherwise.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>Throws:</term>
<listitem>
<para>
Timeout-related exceptions.
</para>
</listitem>
</varlistentry>
</variablelist>
<para>
<bridgehead renderas="sect4" id="recursive_timed_mutex_try_lock_for_bridgehead">
<phrase id="recursive_timed_mutex_try_lock_for"/>
<link linkend="recursive_timed_mutex_try_lock_for">Templated
member function <code>try_lock_for</code>()</link>
</bridgehead>
</para>
<programlisting><phrase role="keyword">template</phrase><phrase role="special">&lt;</phrase> <phrase role="keyword">typename</phrase> <phrase role="identifier">Rep</phrase><phrase role="special">,</phrase> <phrase role="keyword">typename</phrase> <phrase role="identifier">Period</phrase> <phrase role="special">&gt;</phrase>
<phrase role="keyword">bool</phrase> <phrase role="identifier">try_lock_for</phrase><phrase role="special">(</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">chrono</phrase><phrase role="special">::</phrase><phrase role="identifier">duration</phrase><phrase role="special">&lt;</phrase> <phrase role="identifier">Rep</phrase><phrase role="special">,</phrase> <phrase role="identifier">Period</phrase> <phrase role="special">&gt;</phrase> <phrase role="keyword">const</phrase><phrase role="special">&amp;</phrase> <phrase role="identifier">timeout_duration</phrase><phrase role="special">);</phrase>
</programlisting>
<variablelist>
<title></title>
<varlistentry>
<term>Effects:</term>
<listitem>
<para>
Attempt to obtain ownership for the current fiber. Blocks until ownership
can be obtained, or the specified time is reached. If the specified
time has already passed, behaves as <link linkend="recursive_timed_mutex_try_lock"><code>recursive_timed_mutex::try_lock()</code></link>.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>Returns:</term>
<listitem>
<para>
<code><phrase role="keyword">true</phrase></code> if ownership was
obtained for the current fiber, <code><phrase role="keyword">false</phrase></code>
otherwise.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>Throws:</term>
<listitem>
<para>
Timeout-related exceptions.
</para>
</listitem>
</varlistentry>
</variablelist>
</section>
<section id="fiber.synchronization.conditions">
<title><link linkend="fiber.synchronization.conditions">Condition Variables</link></title>
<bridgehead renderas="sect4" id="fiber.synchronization.conditions.h0">
<phrase id="fiber.synchronization.conditions.synopsis"/><link linkend="fiber.synchronization.conditions.synopsis">Synopsis</link>
</bridgehead>
<programlisting><phrase role="keyword">enum</phrase> <phrase role="keyword">class</phrase> <phrase role="identifier">cv_status</phrase><phrase role="special">;</phrase> <phrase role="special">{</phrase>
<phrase role="identifier">no_timeout</phrase><phrase role="special">,</phrase>
<phrase role="identifier">timeout</phrase>
<phrase role="special">};</phrase>
<phrase role="keyword">class</phrase> <phrase role="identifier">condition_variable</phrase><phrase role="special">;</phrase>
<phrase role="keyword">class</phrase> <phrase role="identifier">condition_variable_any</phrase><phrase role="special">;</phrase>
</programlisting>
<para>
The class <link linkend="class_condition_variable"><code>condition_variable</code></link> provides a mechanism
for a fiber to wait for notification from another fiber. When the fiber awakens
from the wait, then it checks to see if the appropriate condition is now
true, and continues if so. If the condition is not true, then the fiber calls
<code><phrase role="identifier">wait</phrase></code> again to resume waiting.
In the simplest case, this condition is just a boolean variable:
</para>
<programlisting><phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">fibers</phrase><phrase role="special">::</phrase><phrase role="identifier">condition_variable</phrase> <phrase role="identifier">cond</phrase><phrase role="special">;</phrase>
<phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">fibers</phrase><phrase role="special">::</phrase><phrase role="identifier">mutex</phrase> <phrase role="identifier">mtx</phrase><phrase role="special">;</phrase>
<phrase role="keyword">bool</phrase> <phrase role="identifier">data_ready</phrase> <phrase role="special">=</phrase> <phrase role="keyword">false</phrase><phrase role="special">;</phrase>
<phrase role="keyword">void</phrase> <phrase role="identifier">process_data</phrase><phrase role="special">();</phrase>
<phrase role="keyword">void</phrase> <phrase role="identifier">wait_for_data_to_process</phrase><phrase role="special">()</phrase> <phrase role="special">{</phrase>
<phrase role="special">{</phrase>
<phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">unique_lock</phrase><phrase role="special">&lt;</phrase> <phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">fibers</phrase><phrase role="special">::</phrase><phrase role="identifier">mutex</phrase> <phrase role="special">&gt;</phrase> <phrase role="identifier">lk</phrase><phrase role="special">(</phrase> <phrase role="identifier">mtx</phrase><phrase role="special">);</phrase>
<phrase role="keyword">while</phrase> <phrase role="special">(</phrase> <phrase role="special">!</phrase> <phrase role="identifier">data_ready</phrase><phrase role="special">)</phrase> <phrase role="special">{</phrase>
<phrase role="identifier">cond</phrase><phrase role="special">.</phrase><phrase role="identifier">wait</phrase><phrase role="special">(</phrase> <phrase role="identifier">lk</phrase><phrase role="special">);</phrase>
<phrase role="special">}</phrase>
<phrase role="special">}</phrase> <phrase role="comment">// release lk</phrase>
<phrase role="identifier">process_data</phrase><phrase role="special">();</phrase>
<phrase role="special">}</phrase>
</programlisting>
<para>
Notice that the <code><phrase role="identifier">lk</phrase></code> is passed
to <link linkend="condition_variable_wait"><code>condition_variable::wait()</code></link>: <code><phrase role="identifier">wait</phrase><phrase
role="special">()</phrase></code> will atomically add the fiber to the set
of fibers waiting on the condition variable, and unlock the <link linkend="class_mutex"><code>mutex</code></link>.
When the fiber is awakened, the <code><phrase role="identifier">mutex</phrase></code>
will be locked again before the call to <code><phrase role="identifier">wait</phrase><phrase
role="special">()</phrase></code> returns. This allows other fibers to acquire
the <code><phrase role="identifier">mutex</phrase></code> in order to update
the shared data, and ensures that the data associated with the condition
is correctly synchronized.
</para>
<para>
<code><phrase role="identifier">wait_for_data_to_process</phrase><phrase
role="special">()</phrase></code> could equivalently be written:
</para>
<programlisting><phrase role="keyword">void</phrase> <phrase role="identifier">wait_for_data_to_process</phrase><phrase role="special">()</phrase> <phrase role="special">{</phrase>
<phrase role="special">{</phrase>
<phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">unique_lock</phrase><phrase role="special">&lt;</phrase> <phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">fibers</phrase><phrase role="special">::</phrase><phrase role="identifier">mutex</phrase> <phrase role="special">&gt;</phrase> <phrase role="identifier">lk</phrase><phrase role="special">(</phrase> <phrase role="identifier">mtx</phrase><phrase role="special">);</phrase>
<phrase role="comment">// make condition_variable::wait() perform the loop</phrase>
<phrase role="identifier">cond</phrase><phrase role="special">.</phrase><phrase role="identifier">wait</phrase><phrase role="special">(</phrase> <phrase role="identifier">lk</phrase><phrase role="special">,</phrase> <phrase role="special">[](){</phrase> <phrase role="keyword">return</phrase> <phrase role="identifier">data_ready</phrase><phrase role="special">;</phrase> <phrase role="special">});</phrase>
<phrase role="special">}</phrase> <phrase role="comment">// release lk</phrase>
<phrase role="identifier">process_data</phrase><phrase role="special">();</phrase>
<phrase role="special">}</phrase>
</programlisting>
<para>
In the meantime, another fiber sets <code><phrase role="identifier">data_ready</phrase></code>
to <code><phrase role="keyword">true</phrase></code>, and then calls either
<link linkend="condition_variable_notify_one"><code>condition_variable::notify_one()</code></link> or <link linkend="condition_variable_notify_all"><code>condition_variable::notify_all()</code></link> on
the <link linkend="class_condition_variable"><code>condition_variable</code></link> <code><phrase role="identifier">cond</phrase></code>
to wake one waiting fiber or all the waiting fibers respectively.
</para>
<programlisting><phrase role="keyword">void</phrase> <phrase role="identifier">retrieve_data</phrase><phrase role="special">();</phrase>
<phrase role="keyword">void</phrase> <phrase role="identifier">prepare_data</phrase><phrase role="special">();</phrase>
<phrase role="keyword">void</phrase> <phrase role="identifier">prepare_data_for_processing</phrase><phrase role="special">()</phrase> <phrase role="special">{</phrase>
<phrase role="identifier">retrieve_data</phrase><phrase role="special">();</phrase>
<phrase role="identifier">prepare_data</phrase><phrase role="special">();</phrase>
<phrase role="special">{</phrase>
<phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">unique_lock</phrase><phrase role="special">&lt;</phrase> <phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">fibers</phrase><phrase role="special">::</phrase><phrase role="identifier">mutex</phrase> <phrase role="special">&gt;</phrase> <phrase role="identifier">lk</phrase><phrase role="special">(</phrase> <phrase role="identifier">mtx</phrase><phrase role="special">);</phrase>
<phrase role="identifier">data_ready</phrase> <phrase role="special">=</phrase> <phrase role="keyword">true</phrase><phrase role="special">;</phrase>
<phrase role="special">}</phrase>
<phrase role="identifier">cond</phrase><phrase role="special">.</phrase><phrase role="identifier">notify_one</phrase><phrase role="special">();</phrase>
<phrase role="special">}</phrase>
</programlisting>
<para>
Note that the same <link linkend="class_mutex"><code>mutex</code></link> is locked before the shared data is updated,
but that the <code><phrase role="identifier">mutex</phrase></code> does not
have to be locked across the call to <link linkend="condition_variable_notify_one"><code>condition_variable::notify_one()</code></link>.
</para>
<para>
Locking is important because the synchronization objects provided by <emphasis
role="bold">Boost.Fiber</emphasis> can be used to synchronize fibers running
on different threads.
</para>
<para>
<emphasis role="bold">Boost.Fiber</emphasis> provides both <link linkend="class_condition_variable"><code>condition_variable</code></link> and
<link linkend="class_condition_variable_any"><code>condition_variable_any</code></link>. <code><phrase role="identifier">boost</phrase><phrase
role="special">::</phrase><phrase role="identifier">fibers</phrase><phrase
role="special">::</phrase><phrase role="identifier">condition_variable</phrase></code>
can only wait on <ulink url="http://en.cppreference.com/w/cpp/thread/unique_lock"><code><phrase
role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">unique_lock</phrase></code></ulink><code><phrase
role="special">&lt;</phrase> <phrase role="identifier">boost</phrase><phrase
role="special">::</phrase><phrase role="identifier">fibers</phrase><phrase
role="special">::</phrase></code><link linkend="class_mutex"><code>mutex</code></link><code> <phrase role="special">&gt;</phrase></code>
while <code><phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase
role="identifier">fibers</phrase><phrase role="special">::</phrase><phrase
role="identifier">condition_variable_any</phrase></code> can wait on user-defined
lock types.
</para>
<anchor id="condition_variable_spurious_wakeups"/>
<bridgehead renderas="sect4" id="fiber.synchronization.conditions.h1">
<phrase id="fiber.synchronization.conditions.no_spurious_wakeups"/><link
linkend="fiber.synchronization.conditions.no_spurious_wakeups">No Spurious
Wakeups</link>
</bridgehead>
<para>
Neither <link linkend="class_condition_variable"><code>condition_variable</code></link> nor <link linkend="class_condition_variable_any"><code>condition_variable_any</code></link> are
subject to spurious wakeup: <link linkend="condition_variable_wait"><code>condition_variable::wait()</code></link> can
only wake up when <link linkend="condition_variable_notify_one"><code>condition_variable::notify_one()</code></link> or
<link linkend="condition_variable_notify_all"><code>condition_variable::notify_all()</code></link> is called. Even
so, it is prudent to use one of the <code><phrase role="identifier">wait</phrase><phrase
role="special">(</phrase> <phrase role="identifier">lock</phrase><phrase
role="special">,</phrase> <phrase role="identifier">predicate</phrase> <phrase
role="special">)</phrase></code> overloads.
</para>
<para>
Consider a set of consumer fibers processing items from a <ulink url="http://en.cppreference.com/w/cpp/container/queue"><code><phrase
role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">queue</phrase></code></ulink>.
The queue is continually populated by a set of producer fibers.
</para>
<para>
The consumer fibers might reasonably wait on a <code><phrase role="identifier">condition_variable</phrase></code>
as long as the queue remains <ulink url="http://en.cppreference.com/w/cpp/container/queue/empty"><code><phrase
role="identifier">empty</phrase><phrase role="special">()</phrase></code></ulink>.
</para>
<para>
Because producer fibers might <ulink url="http://en.cppreference.com/w/cpp/container/queue/push"><code><phrase
role="identifier">push</phrase><phrase role="special">()</phrase></code></ulink>
items to the queue in bursts, they call <link linkend="condition_variable_notify_all"><code>condition_variable::notify_all()</code></link> rather
than <link linkend="condition_variable_notify_one"><code>condition_variable::notify_one()</code></link>.
</para>
<para>
But a given consumer fiber might well wake up from <link linkend="condition_variable_wait"><code>condition_variable::wait()</code></link> and
find the queue <code><phrase role="identifier">empty</phrase><phrase role="special">()</phrase></code>,
because other consumer fibers might already have processed all pending items.
</para>
<para>
(See also <link linkend="spurious_wakeup">spurious wakeup</link>.)
</para>
<anchor id="class_cv_status"/>
<bridgehead renderas="sect4" id="fiber.synchronization.conditions.h2">
<phrase id="fiber.synchronization.conditions.enumeration__code__phrase_role__identifier__cv_status__phrase___code_"/><link
linkend="fiber.synchronization.conditions.enumeration__code__phrase_role__identifier__cv_status__phrase___code_">Enumeration
<code><phrase role="identifier">cv_status</phrase></code></link>
</bridgehead>
<para>
A timed wait operation might return because of timeout or not.
</para>
<programlisting><phrase role="keyword">enum</phrase> <phrase role="keyword">class</phrase> <phrase role="identifier">cv_status</phrase> <phrase role="special">{</phrase>
<phrase role="identifier">no_timeout</phrase><phrase role="special">,</phrase>
<phrase role="identifier">timeout</phrase>
<phrase role="special">};</phrase>
</programlisting>
<bridgehead renderas="sect4" id="fiber.synchronization.conditions.h3">
<phrase id="fiber.synchronization.conditions._code__phrase_role__identifier__no_timeout__phrase___code_"/><link
linkend="fiber.synchronization.conditions._code__phrase_role__identifier__no_timeout__phrase___code_"><code><phrase
role="identifier">no_timeout</phrase></code></link>
</bridgehead>
<variablelist>
<title></title>
<varlistentry>
<term>Effects:</term>
<listitem>
<para>
The condition variable was awakened with <code><phrase role="identifier">notify_one</phrase></code>
or <code><phrase role="identifier">notify_all</phrase></code>.
</para>
</listitem>
</varlistentry>
</variablelist>
<bridgehead renderas="sect4" id="fiber.synchronization.conditions.h4">
<phrase id="fiber.synchronization.conditions._code__phrase_role__identifier__timeout__phrase___code_"/><link
linkend="fiber.synchronization.conditions._code__phrase_role__identifier__timeout__phrase___code_"><code><phrase
role="identifier">timeout</phrase></code></link>
</bridgehead>
<variablelist>
<title></title>
<varlistentry>
<term>Effects:</term>
<listitem>
<para>
The condition variable was awakened by timeout.
</para>
</listitem>
</varlistentry>
</variablelist>
<para>
<bridgehead renderas="sect4" id="class_condition_variable_any_bridgehead">
<phrase id="class_condition_variable_any"/>
<link linkend="class_condition_variable_any">Class
<code>condition_variable_any</code></link>
</bridgehead>
</para>
<programlisting><phrase role="preprocessor">#include</phrase> <phrase role="special">&lt;</phrase><phrase role="identifier">boost</phrase><phrase role="special">/</phrase><phrase role="identifier">fiber</phrase><phrase role="special">/</phrase><phrase role="identifier">condition_variable</phrase><phrase role="special">.</phrase><phrase role="identifier">hpp</phrase><phrase role="special">&gt;</phrase>
<phrase role="keyword">namespace</phrase> <phrase role="identifier">boost</phrase> <phrase role="special">{</phrase>
<phrase role="keyword">namespace</phrase> <phrase role="identifier">fibers</phrase> <phrase role="special">{</phrase>
<phrase role="keyword">class</phrase> condition_variable_any <phrase role="special">{</phrase>
<phrase role="keyword">public</phrase><phrase role="special">:</phrase>
condition_variable_any<phrase role="special">();</phrase>
<phrase role="special">~</phrase>condition_variable_any<phrase role="special">();</phrase>
condition_variable_any<phrase role="special">(</phrase> condition_variable_any <phrase role="keyword">const</phrase><phrase role="special">&amp;)</phrase> <phrase role="special">=</phrase> <phrase role="keyword">delete</phrase><phrase role="special">;</phrase>
condition_variable_any <phrase role="special">&amp;</phrase> <phrase role="keyword">operator</phrase><phrase role="special">=(</phrase> condition_variable_any <phrase role="keyword">const</phrase><phrase role="special">&amp;)</phrase> <phrase role="special">=</phrase> <phrase role="keyword">delete</phrase><phrase role="special">;</phrase>
<phrase role="keyword">void</phrase> <phrase role="identifier">notify_one</phrase><phrase role="special">()</phrase> <phrase role="keyword">noexcept</phrase><phrase role="special">;</phrase>
<phrase role="keyword">void</phrase> <phrase role="identifier">notify_all</phrase><phrase role="special">()</phrase> <phrase role="keyword">noexcept</phrase><phrase role="special">;</phrase>
template&lt; typename LockType &gt;
void <phrase role="identifier">wait</phrase><phrase role="special">(</phrase> LockType <phrase role="special">&amp;);</phrase>
<phrase role="keyword">template</phrase><phrase role="special">&lt;</phrase> typename LockType, typename <phrase role="identifier">Pred</phrase> <phrase role="special">&gt;</phrase>
<phrase role="keyword">void</phrase> <phrase role="identifier">wait</phrase><phrase role="special">(</phrase> LockType <phrase role="special">&amp;,</phrase> <phrase role="identifier">Pred</phrase><phrase role="special">);</phrase>
<phrase role="keyword">template</phrase><phrase role="special">&lt;</phrase> typename LockType, typename <phrase role="identifier">Clock</phrase><phrase role="special">,</phrase> <phrase role="keyword">typename</phrase> <phrase role="identifier">Duration</phrase> <phrase role="special">&gt;</phrase>
<phrase role="identifier">cv_status</phrase> <phrase role="identifier">wait_until</phrase><phrase role="special">(</phrase> LockType <phrase role="special">&amp;,</phrase>
<phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">chrono</phrase><phrase role="special">::</phrase><phrase role="identifier">time_point</phrase><phrase role="special">&lt;</phrase> <phrase role="identifier">Clock</phrase><phrase role="special">,</phrase> <phrase role="identifier">Duration</phrase> <phrase role="special">&gt;</phrase> <phrase role="keyword">const</phrase><phrase role="special">&amp;);</phrase>
<phrase role="keyword">template</phrase><phrase role="special">&lt;</phrase> typename LockType, typename <phrase role="identifier">Clock</phrase><phrase role="special">,</phrase> <phrase role="keyword">typename</phrase> <phrase role="identifier">Duration</phrase><phrase role="special">,</phrase> <phrase role="keyword">typename</phrase> <phrase role="identifier">Pred</phrase> <phrase role="special">&gt;</phrase>
<phrase role="keyword">bool</phrase> <phrase role="identifier">wait_until</phrase><phrase role="special">(</phrase> LockType <phrase role="special">&amp;,</phrase>
<phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">chrono</phrase><phrase role="special">::</phrase><phrase role="identifier">time_point</phrase><phrase role="special">&lt;</phrase> <phrase role="identifier">Clock</phrase><phrase role="special">,</phrase> <phrase role="identifier">Duration</phrase> <phrase role="special">&gt;</phrase> <phrase role="keyword">const</phrase><phrase role="special">&amp;,</phrase>
<phrase role="identifier">Pred</phrase><phrase role="special">);</phrase>
<phrase role="keyword">template</phrase><phrase role="special">&lt;</phrase> typename LockType, typename <phrase role="identifier">Rep</phrase><phrase role="special">,</phrase> <phrase role="keyword">typename</phrase> <phrase role="identifier">Period</phrase> <phrase role="special">&gt;</phrase>
<phrase role="identifier">cv_status</phrase> <phrase role="identifier">wait_for</phrase><phrase role="special">(</phrase> LockType <phrase role="special">&amp;,</phrase>
<phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">chrono</phrase><phrase role="special">::</phrase><phrase role="identifier">duration</phrase><phrase role="special">&lt;</phrase> <phrase role="identifier">Rep</phrase><phrase role="special">,</phrase> <phrase role="identifier">Period</phrase> <phrase role="special">&gt;</phrase> <phrase role="keyword">const</phrase><phrase role="special">&amp;);</phrase>
<phrase role="keyword">template</phrase><phrase role="special">&lt;</phrase> typename LockType, typename <phrase role="identifier">Rep</phrase><phrase role="special">,</phrase> <phrase role="keyword">typename</phrase> <phrase role="identifier">Period</phrase><phrase role="special">,</phrase> <phrase role="keyword">typename</phrase> <phrase role="identifier">Pred</phrase> <phrase role="special">&gt;</phrase>
<phrase role="keyword">bool</phrase> <phrase role="identifier">wait_for</phrase><phrase role="special">(</phrase> LockType <phrase role="special">&amp;,</phrase>
<phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">chrono</phrase><phrase role="special">::</phrase><phrase role="identifier">duration</phrase><phrase role="special">&lt;</phrase> <phrase role="identifier">Rep</phrase><phrase role="special">,</phrase> <phrase role="identifier">Period</phrase> <phrase role="special">&gt;</phrase> <phrase role="keyword">const</phrase><phrase role="special">&amp;,</phrase>
<phrase role="identifier">Pred</phrase><phrase role="special">);</phrase>
<phrase role="special">};</phrase>
<phrase role="special">}}</phrase>
</programlisting>
<bridgehead renderas="sect4" id="fiber.synchronization.conditions.h5">
<phrase id="fiber.synchronization.conditions.constructor"/><link linkend="fiber.synchronization.conditions.constructor">Constructor</link>
</bridgehead>
<programlisting>condition_variable_any<phrase role="special">()</phrase>
</programlisting>
<variablelist>
<title></title>
<varlistentry>
<term>Effects:</term>
<listitem>
<para>
Creates the object.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>Throws:</term>
<listitem>
<para>
Nothing.
</para>
</listitem>
</varlistentry>
</variablelist>
<bridgehead renderas="sect4" id="fiber.synchronization.conditions.h6">
<phrase id="fiber.synchronization.conditions.destructor"/><link linkend="fiber.synchronization.conditions.destructor">Destructor</link>
</bridgehead>
<programlisting><phrase role="special">~</phrase>condition_variable_any<phrase role="special">()</phrase>
</programlisting>
<variablelist>
<title></title>
<varlistentry>
<term>Precondition:</term>
<listitem>
<para>
All fibers waiting on <code><phrase role="special">*</phrase><phrase
role="keyword">this</phrase></code> have been notified by a call to
<code><phrase role="identifier">notify_one</phrase></code> or <code><phrase
role="identifier">notify_all</phrase></code> (though the respective
calls to <code><phrase role="identifier">wait</phrase></code>, <code><phrase
role="identifier">wait_for</phrase></code> or <code><phrase role="identifier">wait_until</phrase></code>
need not have returned).
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>Effects:</term>
<listitem>
<para>
Destroys the object.
</para>
</listitem>
</varlistentry>
</variablelist>
<para>
<bridgehead renderas="sect4" id="condition_variable_any_notify_one_bridgehead">
<phrase id="condition_variable_any_notify_one"/>
<link linkend="condition_variable_any_notify_one">Member
function <code>notify_one</code>()</link>
</bridgehead>
</para>
<programlisting><phrase role="keyword">void</phrase> <phrase role="identifier">notify_one</phrase><phrase role="special">()</phrase> <phrase role="keyword">noexcept</phrase><phrase role="special">;</phrase>
</programlisting>
<variablelist>
<title></title>
<varlistentry>
<term>Effects:</term>
<listitem>
<para>
If any fibers are currently <link linkend="blocking"><emphasis>blocked</emphasis></link>
waiting on <code><phrase role="special">*</phrase><phrase role="keyword">this</phrase></code>
in a call to <code><phrase role="identifier">wait</phrase></code>,
<code><phrase role="identifier">wait_for</phrase></code> or <code><phrase
role="identifier">wait_until</phrase></code>, unblocks one of those
fibers.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>Throws:</term>
<listitem>
<para>
Nothing.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>Note:</term>
<listitem>
<para>
It is arbitrary which waiting fiber is resumed.
</para>
</listitem>
</varlistentry>
</variablelist>
<para>
<bridgehead renderas="sect4" id="condition_variable_any_notify_all_bridgehead">
<phrase id="condition_variable_any_notify_all"/>
<link linkend="condition_variable_any_notify_all">Member
function <code>notify_all</code>()</link>
</bridgehead>
</para>
<programlisting><phrase role="keyword">void</phrase> <phrase role="identifier">notify_all</phrase><phrase role="special">()</phrase> <phrase role="keyword">noexcept</phrase><phrase role="special">;</phrase>
</programlisting>
<variablelist>
<title></title>
<varlistentry>
<term>Effects:</term>
<listitem>
<para>
If any fibers are currently <link linkend="blocking"><emphasis>blocked</emphasis></link>
waiting on <code><phrase role="special">*</phrase><phrase role="keyword">this</phrase></code>
in a call to <code><phrase role="identifier">wait</phrase></code>,
<code><phrase role="identifier">wait_for</phrase></code> or <code><phrase
role="identifier">wait_until</phrase></code>, unblocks all of those
fibers.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>Throws:</term>
<listitem>
<para>
Nothing.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>Note:</term>
<listitem>
<para>
This is why a waiting fiber must <emphasis>also</emphasis> check for
the desired program state using a mechanism external to the <code>condition_variable_any</code>,
and retry the wait until that state is reached. A fiber waiting on
a <code>condition_variable_any</code> might well wake up a number of times before
the desired state is reached.
</para>
</listitem>
</varlistentry>
</variablelist>
<para>
<bridgehead renderas="sect4" id="condition_variable_any_wait_bridgehead">
<phrase id="condition_variable_any_wait"/>
<link linkend="condition_variable_any_wait">Templated
member function <code>wait</code>()</link>
</bridgehead>
</para>
<programlisting>template&lt; typename LockType &gt;
void <phrase role="identifier">wait</phrase><phrase role="special">(</phrase> LockType <phrase role="special">&amp;</phrase> <phrase role="identifier">lk</phrase><phrase role="special">);</phrase>
<phrase role="keyword">template</phrase><phrase role="special">&lt;</phrase> typename LockType, typename <phrase role="identifier">Pred</phrase> <phrase role="special">&gt;</phrase>
<phrase role="keyword">void</phrase> <phrase role="identifier">wait</phrase><phrase role="special">(</phrase> LockType <phrase role="special">&amp;</phrase> <phrase role="identifier">lk</phrase><phrase role="special">,</phrase> <phrase role="identifier">Pred</phrase> <phrase role="identifier">pred</phrase><phrase role="special">);</phrase>
</programlisting>
<variablelist>
<title></title>
<varlistentry>
<term>Precondition:</term>
<listitem>
<para>
<code><phrase role="identifier">lk</phrase></code> is locked by the
current fiber, and either no other fiber is currently waiting on <code><phrase
role="special">*</phrase><phrase role="keyword">this</phrase></code>,
or the execution of the <ulink url="http://en.cppreference.com/w/cpp/thread/unique_lock/mutex"><code><phrase
role="identifier">mutex</phrase><phrase role="special">()</phrase></code></ulink>
member function on the <code><phrase role="identifier">lk</phrase></code>
objects supplied in the calls to <code><phrase role="identifier">wait</phrase></code>
in all the fibers currently waiting on <code><phrase role="special">*</phrase><phrase
role="keyword">this</phrase></code> would return the same value as
<code><phrase role="identifier">lk</phrase><phrase role="special">-&gt;</phrase><phrase
role="identifier">mutex</phrase><phrase role="special">()</phrase></code>
for this call to <code><phrase role="identifier">wait</phrase></code>.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>Effects:</term>
<listitem>
<para>
Atomically call <code><phrase role="identifier">lk</phrase><phrase
role="special">.</phrase><phrase role="identifier">unlock</phrase><phrase
role="special">()</phrase></code> and blocks the current fiber. The
fiber will unblock when notified by a call to <code><phrase role="keyword">this</phrase><phrase
role="special">-&gt;</phrase><phrase role="identifier">notify_one</phrase><phrase
role="special">()</phrase></code> or <code><phrase role="keyword">this</phrase><phrase
role="special">-&gt;</phrase><phrase role="identifier">notify_all</phrase><phrase
role="special">()</phrase></code>. When the fiber is unblocked (for
whatever reason), the lock is reacquired by invoking <code><phrase
role="identifier">lk</phrase><phrase role="special">.</phrase><phrase
role="identifier">lock</phrase><phrase role="special">()</phrase></code>
before the call to <code><phrase role="identifier">wait</phrase></code>
returns. The lock is also reacquired by invoking <code><phrase role="identifier">lk</phrase><phrase
role="special">.</phrase><phrase role="identifier">lock</phrase><phrase
role="special">()</phrase></code> if the function exits with an exception.
The member function accepting <code><phrase role="identifier">pred</phrase></code>
is shorthand for:
<programlisting><phrase role="keyword">while</phrase> <phrase role="special">(</phrase> <phrase role="special">!</phrase> <phrase role="identifier">pred</phrase><phrase role="special">()</phrase> <phrase role="special">)</phrase> <phrase role="special">{</phrase>
<phrase role="identifier">wait</phrase><phrase role="special">(</phrase> <phrase role="identifier">lk</phrase><phrase role="special">);</phrase>
<phrase role="special">}</phrase>
</programlisting>
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>Postcondition:</term>
<listitem>
<para>
<code><phrase role="identifier">lk</phrase></code> is locked by the
current fiber.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>Throws:</term>
<listitem>
<para>
<code><phrase role="identifier">fiber_error</phrase></code> if an error
occurs.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>Note:</term>
<listitem>
<para>
The Precondition is a bit dense. It merely states that all the fibers
concurrently calling <code><phrase role="identifier">wait</phrase></code>
on <code><phrase role="special">*</phrase><phrase role="keyword">this</phrase></code>
must wait on <code><phrase role="identifier">lk</phrase></code> objects
governing the <emphasis>same</emphasis> <link linkend="class_mutex"><code>mutex</code></link>. Three distinct
objects are involved in any <code>condition_variable_any::wait()</code> call: the
<code>condition_variable_any</code> itself, the <code><phrase role="identifier">mutex</phrase></code>
coordinating access between fibers and a local lock object (e.g. <ulink
url="http://en.cppreference.com/w/cpp/thread/unique_lock"><code><phrase
role="identifier">std</phrase><phrase role="special">::</phrase><phrase
role="identifier">unique_lock</phrase></code></ulink>). In general,
you can partition the lifespan of a given <code>condition_variable_any</code> instance
into periods with one or more fibers waiting on it, separated by periods
when no fibers are waiting on it. When more than one fiber is waiting
on that <code>condition_variable_any</code>, all must pass lock objects referencing
the <emphasis>same</emphasis> <code><phrase role="identifier">mutex</phrase></code>
instance.
</para>
</listitem>
</varlistentry>
</variablelist>
<para>
<bridgehead renderas="sect4" id="condition_variable_any_wait_until_bridgehead">
<phrase id="condition_variable_any_wait_until"/>
<link linkend="condition_variable_any_wait_until">Templated
member function <code>wait_until</code>()</link>
</bridgehead>
</para>
<programlisting><phrase role="keyword">template</phrase><phrase role="special">&lt;</phrase> typename LockType, typename <phrase role="identifier">Clock</phrase><phrase role="special">,</phrase> <phrase role="keyword">typename</phrase> <phrase role="identifier">Duration</phrase> <phrase role="special">&gt;</phrase>
<phrase role="identifier">cv_status</phrase> <phrase role="identifier">wait_until</phrase><phrase role="special">(</phrase> LockType <phrase role="special">&amp;</phrase> <phrase role="identifier">lk</phrase><phrase role="special">,</phrase>
<phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">chrono</phrase><phrase role="special">::</phrase><phrase role="identifier">time_point</phrase><phrase role="special">&lt;</phrase> <phrase role="identifier">Clock</phrase><phrase role="special">,</phrase> <phrase role="identifier">Duration</phrase> <phrase role="special">&gt;</phrase> <phrase role="keyword">const</phrase><phrase role="special">&amp;</phrase> <phrase role="identifier">abs_time</phrase><phrase role="special">);</phrase>
<phrase role="keyword">template</phrase><phrase role="special">&lt;</phrase> typename LockType, typename <phrase role="identifier">Clock</phrase><phrase role="special">,</phrase> <phrase role="keyword">typename</phrase> <phrase role="identifier">Duration</phrase><phrase role="special">,</phrase> <phrase role="keyword">typename</phrase> <phrase role="identifier">Pred</phrase> <phrase role="special">&gt;</phrase>
<phrase role="keyword">bool</phrase> <phrase role="identifier">wait_until</phrase><phrase role="special">(</phrase> LockType <phrase role="special">&amp;</phrase> <phrase role="identifier">lk</phrase><phrase role="special">,</phrase>
<phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">chrono</phrase><phrase role="special">::</phrase><phrase role="identifier">time_point</phrase><phrase role="special">&lt;</phrase> <phrase role="identifier">Clock</phrase><phrase role="special">,</phrase> <phrase role="identifier">Duration</phrase> <phrase role="special">&gt;</phrase> <phrase role="keyword">const</phrase><phrase role="special">&amp;</phrase> <phrase role="identifier">abs_time</phrase><phrase role="special">,</phrase>
<phrase role="identifier">Pred</phrase> <phrase role="identifier">pred</phrase><phrase role="special">);</phrase>
</programlisting>
<variablelist>
<title></title>
<varlistentry>
<term>Precondition:</term>
<listitem>
<para>
<code><phrase role="identifier">lk</phrase></code> is locked by the
current fiber, and either no other fiber is currently waiting on <code><phrase
role="special">*</phrase><phrase role="keyword">this</phrase></code>,
or the execution of the <code><phrase role="identifier">mutex</phrase><phrase
role="special">()</phrase></code> member function on the <code><phrase
role="identifier">lk</phrase></code> objects supplied in the calls
to <code><phrase role="identifier">wait</phrase></code>, <code><phrase
role="identifier">wait_for</phrase></code> or <code><phrase role="identifier">wait_until</phrase></code>
in all the fibers currently waiting on <code><phrase role="special">*</phrase><phrase
role="keyword">this</phrase></code> would return the same value as
<code><phrase role="identifier">lk</phrase><phrase role="special">.</phrase><phrase
role="identifier">mutex</phrase><phrase role="special">()</phrase></code>
for this call to <code><phrase role="identifier">wait_until</phrase></code>.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>Effects:</term>
<listitem>
<para>
Atomically call <code><phrase role="identifier">lk</phrase><phrase
role="special">.</phrase><phrase role="identifier">unlock</phrase><phrase
role="special">()</phrase></code> and blocks the current fiber. The
fiber will unblock when notified by a call to <code><phrase role="keyword">this</phrase><phrase
role="special">-&gt;</phrase><phrase role="identifier">notify_one</phrase><phrase
role="special">()</phrase></code> or <code><phrase role="keyword">this</phrase><phrase
role="special">-&gt;</phrase><phrase role="identifier">notify_all</phrase><phrase
role="special">()</phrase></code>, when the system time would be equal
to or later than the specified <code><phrase role="identifier">abs_time</phrase></code>.
When the fiber is unblocked (for whatever reason), the lock is reacquired
by invoking <code><phrase role="identifier">lk</phrase><phrase role="special">.</phrase><phrase
role="identifier">lock</phrase><phrase role="special">()</phrase></code>
before the call to <code><phrase role="identifier">wait_until</phrase></code>
returns. The lock is also reacquired by invoking <code><phrase role="identifier">lk</phrase><phrase
role="special">.</phrase><phrase role="identifier">lock</phrase><phrase
role="special">()</phrase></code> if the function exits with an exception.
The member function accepting <code><phrase role="identifier">pred</phrase></code>
is shorthand for:
<programlisting><phrase role="keyword">while</phrase> <phrase role="special">(</phrase> <phrase role="special">!</phrase> <phrase role="identifier">pred</phrase><phrase role="special">()</phrase> <phrase role="special">)</phrase> <phrase role="special">{</phrase>
<phrase role="keyword">if</phrase> <phrase role="special">(</phrase> <phrase role="identifier">cv_status</phrase><phrase role="special">::</phrase><phrase role="identifier">timeout</phrase> <phrase role="special">==</phrase> <phrase role="identifier">wait_until</phrase><phrase role="special">(</phrase> <phrase role="identifier">lk</phrase><phrase role="special">,</phrase> <phrase role="identifier">abs_time</phrase><phrase role="special">)</phrase> <phrase role="special">)</phrase>
<phrase role="keyword">return</phrase> <phrase role="identifier">pred</phrase><phrase role="special">();</phrase>
<phrase role="special">}</phrase>
<phrase role="keyword">return</phrase> <phrase role="keyword">true</phrase><phrase role="special">;</phrase>
</programlisting>
That is, even if <code><phrase role="identifier">wait_until</phrase><phrase
role="special">()</phrase></code> times out, it can still return <code><phrase
role="keyword">true</phrase></code> if <code><phrase role="identifier">pred</phrase><phrase
role="special">()</phrase></code> returns <code><phrase role="keyword">true</phrase></code>
at that time.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>Postcondition:</term>
<listitem>
<para>
<code><phrase role="identifier">lk</phrase></code> is locked by the
current fiber.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>Throws:</term>
<listitem>
<para>
<code><phrase role="identifier">fiber_error</phrase></code> if an error
occurs or timeout-related exceptions.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>Returns:</term>
<listitem>
<para>
The overload without <code><phrase role="identifier">pred</phrase></code>
returns <code><phrase role="identifier">cv_status</phrase><phrase role="special">::</phrase><phrase
role="identifier">no_timeout</phrase></code> if awakened by <code><phrase
role="identifier">notify_one</phrase><phrase role="special">()</phrase></code>
or <code><phrase role="identifier">notify_all</phrase><phrase role="special">()</phrase></code>,
or <code><phrase role="identifier">cv_status</phrase><phrase role="special">::</phrase><phrase
role="identifier">timeout</phrase></code> if awakened because the system
time is past <code><phrase role="identifier">abs_time</phrase></code>.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>Returns:</term>
<listitem>
<para>
The overload accepting <code><phrase role="identifier">pred</phrase></code>
returns <code><phrase role="keyword">false</phrase></code> if the call
is returning because the time specified by <code><phrase role="identifier">abs_time</phrase></code>
was reached and the predicate returns <code><phrase role="keyword">false</phrase></code>,
<code><phrase role="keyword">true</phrase></code> otherwise.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>Note:</term>
<listitem>
<para>
See <emphasis role="bold">Note</emphasis> for <link linkend="condition_variable_any_wait"><code>condition_variable_any::wait()</code></link>.
</para>
</listitem>
</varlistentry>
</variablelist>
<para>
<bridgehead renderas="sect4" id="condition_variable_any_wait_for_bridgehead">
<phrase id="condition_variable_any_wait_for"/>
<link linkend="condition_variable_any_wait_for">Templated
member function <code>wait_for</code>()</link>
</bridgehead>
</para>
<programlisting><phrase role="keyword">template</phrase><phrase role="special">&lt;</phrase> typename LockType, typename <phrase role="identifier">Rep</phrase><phrase role="special">,</phrase> <phrase role="keyword">typename</phrase> <phrase role="identifier">Period</phrase> <phrase role="special">&gt;</phrase>
<phrase role="identifier">cv_status</phrase> <phrase role="identifier">wait_for</phrase><phrase role="special">(</phrase> LockType <phrase role="special">&amp;</phrase> <phrase role="identifier">lk</phrase><phrase role="special">,</phrase>
<phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">chrono</phrase><phrase role="special">::</phrase><phrase role="identifier">duration</phrase><phrase role="special">&lt;</phrase> <phrase role="identifier">Rep</phrase><phrase role="special">,</phrase> <phrase role="identifier">Period</phrase> <phrase role="special">&gt;</phrase> <phrase role="keyword">const</phrase><phrase role="special">&amp;</phrase> <phrase role="identifier">rel_time</phrase><phrase role="special">);</phrase>
<phrase role="keyword">template</phrase><phrase role="special">&lt;</phrase> typename LockType, typename <phrase role="identifier">Rep</phrase><phrase role="special">,</phrase> <phrase role="keyword">typename</phrase> <phrase role="identifier">Period</phrase><phrase role="special">,</phrase> <phrase role="keyword">typename</phrase> <phrase role="identifier">Pred</phrase> <phrase role="special">&gt;</phrase>
<phrase role="keyword">bool</phrase> <phrase role="identifier">wait_for</phrase><phrase role="special">(</phrase> LockType <phrase role="special">&amp;</phrase> <phrase role="identifier">lk</phrase><phrase role="special">,</phrase>
<phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">chrono</phrase><phrase role="special">::</phrase><phrase role="identifier">duration</phrase><phrase role="special">&lt;</phrase> <phrase role="identifier">Rep</phrase><phrase role="special">,</phrase> <phrase role="identifier">Period</phrase> <phrase role="special">&gt;</phrase> <phrase role="keyword">const</phrase><phrase role="special">&amp;</phrase> <phrase role="identifier">rel_time</phrase><phrase role="special">,</phrase>
<phrase role="identifier">Pred</phrase> <phrase role="identifier">pred</phrase><phrase role="special">);</phrase>
</programlisting>
<variablelist>
<title></title>
<varlistentry>
<term>Precondition:</term>
<listitem>
<para>
<code><phrase role="identifier">lk</phrase></code> is locked by the
current fiber, and either no other fiber is currently waiting on <code><phrase
role="special">*</phrase><phrase role="keyword">this</phrase></code>,
or the execution of the <code><phrase role="identifier">mutex</phrase><phrase
role="special">()</phrase></code> member function on the <code><phrase
role="identifier">lk</phrase></code> objects supplied in the calls
to <code><phrase role="identifier">wait</phrase></code>, <code><phrase
role="identifier">wait_for</phrase></code> or <code><phrase role="identifier">wait_until</phrase></code>
in all the fibers currently waiting on <code><phrase role="special">*</phrase><phrase
role="keyword">this</phrase></code> would return the same value as
<code><phrase role="identifier">lk</phrase><phrase role="special">.</phrase><phrase
role="identifier">mutex</phrase><phrase role="special">()</phrase></code>
for this call to <code><phrase role="identifier">wait_for</phrase></code>.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>Effects:</term>
<listitem>
<para>
Atomically call <code><phrase role="identifier">lk</phrase><phrase
role="special">.</phrase><phrase role="identifier">unlock</phrase><phrase
role="special">()</phrase></code> and blocks the current fiber. The
fiber will unblock when notified by a call to <code><phrase role="keyword">this</phrase><phrase
role="special">-&gt;</phrase><phrase role="identifier">notify_one</phrase><phrase
role="special">()</phrase></code> or <code><phrase role="keyword">this</phrase><phrase
role="special">-&gt;</phrase><phrase role="identifier">notify_all</phrase><phrase
role="special">()</phrase></code>, when a time interval equal to or
greater than the specified <code><phrase role="identifier">rel_time</phrase></code>
has elapsed. When the fiber is unblocked (for whatever reason), the
lock is reacquired by invoking <code><phrase role="identifier">lk</phrase><phrase
role="special">.</phrase><phrase role="identifier">lock</phrase><phrase
role="special">()</phrase></code> before the call to <code><phrase
role="identifier">wait</phrase></code> returns. The lock is also reacquired
by invoking <code><phrase role="identifier">lk</phrase><phrase role="special">.</phrase><phrase
role="identifier">lock</phrase><phrase role="special">()</phrase></code>
if the function exits with an exception. The <code><phrase role="identifier">wait_for</phrase><phrase
role="special">()</phrase></code> member function accepting <code><phrase
role="identifier">pred</phrase></code> is shorthand for:
<programlisting><phrase role="keyword">while</phrase> <phrase role="special">(</phrase> <phrase role="special">!</phrase> <phrase role="identifier">pred</phrase><phrase role="special">()</phrase> <phrase role="special">)</phrase> <phrase role="special">{</phrase>
<phrase role="keyword">if</phrase> <phrase role="special">(</phrase> <phrase role="identifier">cv_status</phrase><phrase role="special">::</phrase><phrase role="identifier">timeout</phrase> <phrase role="special">==</phrase> <phrase role="identifier">wait_for</phrase><phrase role="special">(</phrase> <phrase role="identifier">lk</phrase><phrase role="special">,</phrase> <phrase role="identifier">rel_time</phrase><phrase role="special">)</phrase> <phrase role="special">)</phrase> <phrase role="special">{</phrase>
<phrase role="keyword">return</phrase> <phrase role="identifier">pred</phrase><phrase role="special">();</phrase>
<phrase role="special">}</phrase>
<phrase role="special">}</phrase>
<phrase role="keyword">return</phrase> <phrase role="keyword">true</phrase><phrase role="special">;</phrase>
</programlisting>
(except of course that <code><phrase role="identifier">rel_time</phrase></code>
is adjusted for each iteration). The point is that, even if <code><phrase
role="identifier">wait_for</phrase><phrase role="special">()</phrase></code>
times out, it can still return <code><phrase role="keyword">true</phrase></code>
if <code><phrase role="identifier">pred</phrase><phrase role="special">()</phrase></code>
returns <code><phrase role="keyword">true</phrase></code> at that time.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>Postcondition:</term>
<listitem>
<para>
<code><phrase role="identifier">lk</phrase></code> is locked by the
current fiber.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>Throws:</term>
<listitem>
<para>
<code><phrase role="identifier">fiber_error</phrase></code> if an error
occurs or timeout-related exceptions.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>Returns:</term>
<listitem>
<para>
The overload without <code><phrase role="identifier">pred</phrase></code>
returns <code><phrase role="identifier">cv_status</phrase><phrase role="special">::</phrase><phrase
role="identifier">no_timeout</phrase></code> if awakened by <code><phrase
role="identifier">notify_one</phrase><phrase role="special">()</phrase></code>
or <code><phrase role="identifier">notify_all</phrase><phrase role="special">()</phrase></code>,
or <code><phrase role="identifier">cv_status</phrase><phrase role="special">::</phrase><phrase
role="identifier">timeout</phrase></code> if awakened because at least
<code><phrase role="identifier">rel_time</phrase></code> has elapsed.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>Returns:</term>
<listitem>
<para>
The overload accepting <code><phrase role="identifier">pred</phrase></code>
returns <code><phrase role="keyword">false</phrase></code> if the call
is returning because at least <code><phrase role="identifier">rel_time</phrase></code>
has elapsed and the predicate returns <code><phrase role="keyword">false</phrase></code>,
<code><phrase role="keyword">true</phrase></code> otherwise.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>Note:</term>
<listitem>
<para>
See <emphasis role="bold">Note</emphasis> for <link linkend="condition_variable_any_wait"><code>condition_variable_any::wait()</code></link>.
</para>
</listitem>
</varlistentry>
</variablelist>
<para>
<bridgehead renderas="sect4" id="class_condition_variable_bridgehead">
<phrase id="class_condition_variable"/>
<link linkend="class_condition_variable">Class
<code>condition_variable</code></link>
</bridgehead>
</para>
<programlisting><phrase role="preprocessor">#include</phrase> <phrase role="special">&lt;</phrase><phrase role="identifier">boost</phrase><phrase role="special">/</phrase><phrase role="identifier">fiber</phrase><phrase role="special">/</phrase><phrase role="identifier">condition_variable</phrase><phrase role="special">.</phrase><phrase role="identifier">hpp</phrase><phrase role="special">&gt;</phrase>
<phrase role="keyword">namespace</phrase> <phrase role="identifier">boost</phrase> <phrase role="special">{</phrase>
<phrase role="keyword">namespace</phrase> <phrase role="identifier">fibers</phrase> <phrase role="special">{</phrase>
<phrase role="keyword">class</phrase> condition_variable <phrase role="special">{</phrase>
<phrase role="keyword">public</phrase><phrase role="special">:</phrase>
condition_variable<phrase role="special">();</phrase>
<phrase role="special">~</phrase>condition_variable<phrase role="special">();</phrase>
condition_variable<phrase role="special">(</phrase> condition_variable <phrase role="keyword">const</phrase><phrase role="special">&amp;)</phrase> <phrase role="special">=</phrase> <phrase role="keyword">delete</phrase><phrase role="special">;</phrase>
condition_variable <phrase role="special">&amp;</phrase> <phrase role="keyword">operator</phrase><phrase role="special">=(</phrase> condition_variable <phrase role="keyword">const</phrase><phrase role="special">&amp;)</phrase> <phrase role="special">=</phrase> <phrase role="keyword">delete</phrase><phrase role="special">;</phrase>
<phrase role="keyword">void</phrase> <phrase role="identifier">notify_one</phrase><phrase role="special">()</phrase> <phrase role="keyword">noexcept</phrase><phrase role="special">;</phrase>
<phrase role="keyword">void</phrase> <phrase role="identifier">notify_all</phrase><phrase role="special">()</phrase> <phrase role="keyword">noexcept</phrase><phrase role="special">;</phrase>
void <phrase role="identifier">wait</phrase><phrase role="special">(</phrase> std::unique_lock&lt; mutex &gt; <phrase role="special">&amp;);</phrase>
<phrase role="keyword">template</phrase><phrase role="special">&lt;</phrase> typename <phrase role="identifier">Pred</phrase> <phrase role="special">&gt;</phrase>
<phrase role="keyword">void</phrase> <phrase role="identifier">wait</phrase><phrase role="special">(</phrase> std::unique_lock&lt; mutex &gt; <phrase role="special">&amp;,</phrase> <phrase role="identifier">Pred</phrase><phrase role="special">);</phrase>
<phrase role="keyword">template</phrase><phrase role="special">&lt;</phrase> typename <phrase role="identifier">Clock</phrase><phrase role="special">,</phrase> <phrase role="keyword">typename</phrase> <phrase role="identifier">Duration</phrase> <phrase role="special">&gt;</phrase>
<phrase role="identifier">cv_status</phrase> <phrase role="identifier">wait_until</phrase><phrase role="special">(</phrase> std::unique_lock&lt; mutex &gt; <phrase role="special">&amp;,</phrase>
<phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">chrono</phrase><phrase role="special">::</phrase><phrase role="identifier">time_point</phrase><phrase role="special">&lt;</phrase> <phrase role="identifier">Clock</phrase><phrase role="special">,</phrase> <phrase role="identifier">Duration</phrase> <phrase role="special">&gt;</phrase> <phrase role="keyword">const</phrase><phrase role="special">&amp;);</phrase>
<phrase role="keyword">template</phrase><phrase role="special">&lt;</phrase> typename <phrase role="identifier">Clock</phrase><phrase role="special">,</phrase> <phrase role="keyword">typename</phrase> <phrase role="identifier">Duration</phrase><phrase role="special">,</phrase> <phrase role="keyword">typename</phrase> <phrase role="identifier">Pred</phrase> <phrase role="special">&gt;</phrase>
<phrase role="keyword">bool</phrase> <phrase role="identifier">wait_until</phrase><phrase role="special">(</phrase> std::unique_lock&lt; mutex &gt; <phrase role="special">&amp;,</phrase>
<phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">chrono</phrase><phrase role="special">::</phrase><phrase role="identifier">time_point</phrase><phrase role="special">&lt;</phrase> <phrase role="identifier">Clock</phrase><phrase role="special">,</phrase> <phrase role="identifier">Duration</phrase> <phrase role="special">&gt;</phrase> <phrase role="keyword">const</phrase><phrase role="special">&amp;,</phrase>
<phrase role="identifier">Pred</phrase><phrase role="special">);</phrase>
<phrase role="keyword">template</phrase><phrase role="special">&lt;</phrase> typename <phrase role="identifier">Rep</phrase><phrase role="special">,</phrase> <phrase role="keyword">typename</phrase> <phrase role="identifier">Period</phrase> <phrase role="special">&gt;</phrase>
<phrase role="identifier">cv_status</phrase> <phrase role="identifier">wait_for</phrase><phrase role="special">(</phrase> std::unique_lock&lt; mutex &gt; <phrase role="special">&amp;,</phrase>
<phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">chrono</phrase><phrase role="special">::</phrase><phrase role="identifier">duration</phrase><phrase role="special">&lt;</phrase> <phrase role="identifier">Rep</phrase><phrase role="special">,</phrase> <phrase role="identifier">Period</phrase> <phrase role="special">&gt;</phrase> <phrase role="keyword">const</phrase><phrase role="special">&amp;);</phrase>
<phrase role="keyword">template</phrase><phrase role="special">&lt;</phrase> typename <phrase role="identifier">Rep</phrase><phrase role="special">,</phrase> <phrase role="keyword">typename</phrase> <phrase role="identifier">Period</phrase><phrase role="special">,</phrase> <phrase role="keyword">typename</phrase> <phrase role="identifier">Pred</phrase> <phrase role="special">&gt;</phrase>
<phrase role="keyword">bool</phrase> <phrase role="identifier">wait_for</phrase><phrase role="special">(</phrase> std::unique_lock&lt; mutex &gt; <phrase role="special">&amp;,</phrase>
<phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">chrono</phrase><phrase role="special">::</phrase><phrase role="identifier">duration</phrase><phrase role="special">&lt;</phrase> <phrase role="identifier">Rep</phrase><phrase role="special">,</phrase> <phrase role="identifier">Period</phrase> <phrase role="special">&gt;</phrase> <phrase role="keyword">const</phrase><phrase role="special">&amp;,</phrase>
<phrase role="identifier">Pred</phrase><phrase role="special">);</phrase>
<phrase role="special">};</phrase>
<phrase role="special">}}</phrase>
</programlisting>
<bridgehead renderas="sect4" id="fiber.synchronization.conditions.h7">
<phrase id="fiber.synchronization.conditions.constructor0"/><link linkend="fiber.synchronization.conditions.constructor0">Constructor</link>
</bridgehead>
<programlisting>condition_variable<phrase role="special">()</phrase>
</programlisting>
<variablelist>
<title></title>
<varlistentry>
<term>Effects:</term>
<listitem>
<para>
Creates the object.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>Throws:</term>
<listitem>
<para>
Nothing.
</para>
</listitem>
</varlistentry>
</variablelist>
<bridgehead renderas="sect4" id="fiber.synchronization.conditions.h8">
<phrase id="fiber.synchronization.conditions.destructor0"/><link linkend="fiber.synchronization.conditions.destructor0">Destructor</link>
</bridgehead>
<programlisting><phrase role="special">~</phrase>condition_variable<phrase role="special">()</phrase>
</programlisting>
<variablelist>
<title></title>
<varlistentry>
<term>Precondition:</term>
<listitem>
<para>
All fibers waiting on <code><phrase role="special">*</phrase><phrase
role="keyword">this</phrase></code> have been notified by a call to
<code><phrase role="identifier">notify_one</phrase></code> or <code><phrase
role="identifier">notify_all</phrase></code> (though the respective
calls to <code><phrase role="identifier">wait</phrase></code>, <code><phrase
role="identifier">wait_for</phrase></code> or <code><phrase role="identifier">wait_until</phrase></code>
need not have returned).
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>Effects:</term>
<listitem>
<para>
Destroys the object.
</para>
</listitem>
</varlistentry>
</variablelist>
<para>
<bridgehead renderas="sect4" id="condition_variable_notify_one_bridgehead">
<phrase id="condition_variable_notify_one"/>
<link linkend="condition_variable_notify_one">Member
function <code>notify_one</code>()</link>
</bridgehead>
</para>
<programlisting><phrase role="keyword">void</phrase> <phrase role="identifier">notify_one</phrase><phrase role="special">()</phrase> <phrase role="keyword">noexcept</phrase><phrase role="special">;</phrase>
</programlisting>
<variablelist>
<title></title>
<varlistentry>
<term>Effects:</term>
<listitem>
<para>
If any fibers are currently <link linkend="blocking"><emphasis>blocked</emphasis></link>
waiting on <code><phrase role="special">*</phrase><phrase role="keyword">this</phrase></code>
in a call to <code><phrase role="identifier">wait</phrase></code>,
<code><phrase role="identifier">wait_for</phrase></code> or <code><phrase
role="identifier">wait_until</phrase></code>, unblocks one of those
fibers.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>Throws:</term>
<listitem>
<para>
Nothing.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>Note:</term>
<listitem>
<para>
It is arbitrary which waiting fiber is resumed.
</para>
</listitem>
</varlistentry>
</variablelist>
<para>
<bridgehead renderas="sect4" id="condition_variable_notify_all_bridgehead">
<phrase id="condition_variable_notify_all"/>
<link linkend="condition_variable_notify_all">Member
function <code>notify_all</code>()</link>
</bridgehead>
</para>
<programlisting><phrase role="keyword">void</phrase> <phrase role="identifier">notify_all</phrase><phrase role="special">()</phrase> <phrase role="keyword">noexcept</phrase><phrase role="special">;</phrase>
</programlisting>
<variablelist>
<title></title>
<varlistentry>
<term>Effects:</term>
<listitem>
<para>
If any fibers are currently <link linkend="blocking"><emphasis>blocked</emphasis></link>
waiting on <code><phrase role="special">*</phrase><phrase role="keyword">this</phrase></code>
in a call to <code><phrase role="identifier">wait</phrase></code>,
<code><phrase role="identifier">wait_for</phrase></code> or <code><phrase
role="identifier">wait_until</phrase></code>, unblocks all of those
fibers.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>Throws:</term>
<listitem>
<para>
Nothing.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>Note:</term>
<listitem>
<para>
This is why a waiting fiber must <emphasis>also</emphasis> check for
the desired program state using a mechanism external to the <code>condition_variable</code>,
and retry the wait until that state is reached. A fiber waiting on
a <code>condition_variable</code> might well wake up a number of times before the
desired state is reached.
</para>
</listitem>
</varlistentry>
</variablelist>
<para>
<bridgehead renderas="sect4" id="condition_variable_wait_bridgehead">
<phrase id="condition_variable_wait"/>
<link linkend="condition_variable_wait">Templated
member function <code>wait</code>()</link>
</bridgehead>
</para>
<programlisting>void <phrase role="identifier">wait</phrase><phrase role="special">(</phrase> std::unique_lock&lt; mutex &gt; <phrase role="special">&amp;</phrase> <phrase role="identifier">lk</phrase><phrase role="special">);</phrase>
<phrase role="keyword">template</phrase><phrase role="special">&lt;</phrase> typename <phrase role="identifier">Pred</phrase> <phrase role="special">&gt;</phrase>
<phrase role="keyword">void</phrase> <phrase role="identifier">wait</phrase><phrase role="special">(</phrase> std::unique_lock&lt; mutex &gt; <phrase role="special">&amp;</phrase> <phrase role="identifier">lk</phrase><phrase role="special">,</phrase> <phrase role="identifier">Pred</phrase> <phrase role="identifier">pred</phrase><phrase role="special">);</phrase>
</programlisting>
<variablelist>
<title></title>
<varlistentry>
<term>Precondition:</term>
<listitem>
<para>
<code><phrase role="identifier">lk</phrase></code> is locked by the
current fiber, and either no other fiber is currently waiting on <code><phrase
role="special">*</phrase><phrase role="keyword">this</phrase></code>,
or the execution of the <ulink url="http://en.cppreference.com/w/cpp/thread/unique_lock/mutex"><code><phrase
role="identifier">mutex</phrase><phrase role="special">()</phrase></code></ulink>
member function on the <code><phrase role="identifier">lk</phrase></code>
objects supplied in the calls to <code><phrase role="identifier">wait</phrase></code>
in all the fibers currently waiting on <code><phrase role="special">*</phrase><phrase
role="keyword">this</phrase></code> would return the same value as
<code><phrase role="identifier">lk</phrase><phrase role="special">-&gt;</phrase><phrase
role="identifier">mutex</phrase><phrase role="special">()</phrase></code>
for this call to <code><phrase role="identifier">wait</phrase></code>.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>Effects:</term>
<listitem>
<para>
Atomically call <code><phrase role="identifier">lk</phrase><phrase
role="special">.</phrase><phrase role="identifier">unlock</phrase><phrase
role="special">()</phrase></code> and blocks the current fiber. The
fiber will unblock when notified by a call to <code><phrase role="keyword">this</phrase><phrase
role="special">-&gt;</phrase><phrase role="identifier">notify_one</phrase><phrase
role="special">()</phrase></code> or <code><phrase role="keyword">this</phrase><phrase
role="special">-&gt;</phrase><phrase role="identifier">notify_all</phrase><phrase
role="special">()</phrase></code>. When the fiber is unblocked (for
whatever reason), the lock is reacquired by invoking <code><phrase
role="identifier">lk</phrase><phrase role="special">.</phrase><phrase
role="identifier">lock</phrase><phrase role="special">()</phrase></code>
before the call to <code><phrase role="identifier">wait</phrase></code>
returns. The lock is also reacquired by invoking <code><phrase role="identifier">lk</phrase><phrase
role="special">.</phrase><phrase role="identifier">lock</phrase><phrase
role="special">()</phrase></code> if the function exits with an exception.
The member function accepting <code><phrase role="identifier">pred</phrase></code>
is shorthand for:
<programlisting><phrase role="keyword">while</phrase> <phrase role="special">(</phrase> <phrase role="special">!</phrase> <phrase role="identifier">pred</phrase><phrase role="special">()</phrase> <phrase role="special">)</phrase> <phrase role="special">{</phrase>
<phrase role="identifier">wait</phrase><phrase role="special">(</phrase> <phrase role="identifier">lk</phrase><phrase role="special">);</phrase>
<phrase role="special">}</phrase>
</programlisting>
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>Postcondition:</term>
<listitem>
<para>
<code><phrase role="identifier">lk</phrase></code> is locked by the
current fiber.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>Throws:</term>
<listitem>
<para>
<code><phrase role="identifier">fiber_error</phrase></code> if an error
occurs.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>Note:</term>
<listitem>
<para>
The Precondition is a bit dense. It merely states that all the fibers
concurrently calling <code><phrase role="identifier">wait</phrase></code>
on <code><phrase role="special">*</phrase><phrase role="keyword">this</phrase></code>
must wait on <code><phrase role="identifier">lk</phrase></code> objects
governing the <emphasis>same</emphasis> <link linkend="class_mutex"><code>mutex</code></link>. Three distinct
objects are involved in any <code>condition_variable::wait()</code> call: the <code>condition_variable</code> itself,
the <code><phrase role="identifier">mutex</phrase></code> coordinating
access between fibers and a local lock object (e.g. <ulink url="http://en.cppreference.com/w/cpp/thread/unique_lock"><code><phrase
role="identifier">std</phrase><phrase role="special">::</phrase><phrase
role="identifier">unique_lock</phrase></code></ulink>). In general,
you can partition the lifespan of a given <code>condition_variable</code> instance
into periods with one or more fibers waiting on it, separated by periods
when no fibers are waiting on it. When more than one fiber is waiting
on that <code>condition_variable</code>, all must pass lock objects referencing
the <emphasis>same</emphasis> <code><phrase role="identifier">mutex</phrase></code>
instance.
</para>
</listitem>
</varlistentry>
</variablelist>
<para>
<bridgehead renderas="sect4" id="condition_variable_wait_until_bridgehead">
<phrase id="condition_variable_wait_until"/>
<link linkend="condition_variable_wait_until">Templated
member function <code>wait_until</code>()</link>
</bridgehead>
</para>
<programlisting><phrase role="keyword">template</phrase><phrase role="special">&lt;</phrase> typename <phrase role="identifier">Clock</phrase><phrase role="special">,</phrase> <phrase role="keyword">typename</phrase> <phrase role="identifier">Duration</phrase> <phrase role="special">&gt;</phrase>
<phrase role="identifier">cv_status</phrase> <phrase role="identifier">wait_until</phrase><phrase role="special">(</phrase> std::unique_lock&lt; mutex &gt; <phrase role="special">&amp;</phrase> <phrase role="identifier">lk</phrase><phrase role="special">,</phrase>
<phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">chrono</phrase><phrase role="special">::</phrase><phrase role="identifier">time_point</phrase><phrase role="special">&lt;</phrase> <phrase role="identifier">Clock</phrase><phrase role="special">,</phrase> <phrase role="identifier">Duration</phrase> <phrase role="special">&gt;</phrase> <phrase role="keyword">const</phrase><phrase role="special">&amp;</phrase> <phrase role="identifier">abs_time</phrase><phrase role="special">);</phrase>
<phrase role="keyword">template</phrase><phrase role="special">&lt;</phrase> typename <phrase role="identifier">Clock</phrase><phrase role="special">,</phrase> <phrase role="keyword">typename</phrase> <phrase role="identifier">Duration</phrase><phrase role="special">,</phrase> <phrase role="keyword">typename</phrase> <phrase role="identifier">Pred</phrase> <phrase role="special">&gt;</phrase>
<phrase role="keyword">bool</phrase> <phrase role="identifier">wait_until</phrase><phrase role="special">(</phrase> std::unique_lock&lt; mutex &gt; <phrase role="special">&amp;</phrase> <phrase role="identifier">lk</phrase><phrase role="special">,</phrase>
<phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">chrono</phrase><phrase role="special">::</phrase><phrase role="identifier">time_point</phrase><phrase role="special">&lt;</phrase> <phrase role="identifier">Clock</phrase><phrase role="special">,</phrase> <phrase role="identifier">Duration</phrase> <phrase role="special">&gt;</phrase> <phrase role="keyword">const</phrase><phrase role="special">&amp;</phrase> <phrase role="identifier">abs_time</phrase><phrase role="special">,</phrase>
<phrase role="identifier">Pred</phrase> <phrase role="identifier">pred</phrase><phrase role="special">);</phrase>
</programlisting>
<variablelist>
<title></title>
<varlistentry>
<term>Precondition:</term>
<listitem>
<para>
<code><phrase role="identifier">lk</phrase></code> is locked by the
current fiber, and either no other fiber is currently waiting on <code><phrase
role="special">*</phrase><phrase role="keyword">this</phrase></code>,
or the execution of the <code><phrase role="identifier">mutex</phrase><phrase
role="special">()</phrase></code> member function on the <code><phrase
role="identifier">lk</phrase></code> objects supplied in the calls
to <code><phrase role="identifier">wait</phrase></code>, <code><phrase
role="identifier">wait_for</phrase></code> or <code><phrase role="identifier">wait_until</phrase></code>
in all the fibers currently waiting on <code><phrase role="special">*</phrase><phrase
role="keyword">this</phrase></code> would return the same value as
<code><phrase role="identifier">lk</phrase><phrase role="special">.</phrase><phrase
role="identifier">mutex</phrase><phrase role="special">()</phrase></code>
for this call to <code><phrase role="identifier">wait_until</phrase></code>.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>Effects:</term>
<listitem>
<para>
Atomically call <code><phrase role="identifier">lk</phrase><phrase
role="special">.</phrase><phrase role="identifier">unlock</phrase><phrase
role="special">()</phrase></code> and blocks the current fiber. The
fiber will unblock when notified by a call to <code><phrase role="keyword">this</phrase><phrase
role="special">-&gt;</phrase><phrase role="identifier">notify_one</phrase><phrase
role="special">()</phrase></code> or <code><phrase role="keyword">this</phrase><phrase
role="special">-&gt;</phrase><phrase role="identifier">notify_all</phrase><phrase
role="special">()</phrase></code>, when the system time would be equal
to or later than the specified <code><phrase role="identifier">abs_time</phrase></code>.
When the fiber is unblocked (for whatever reason), the lock is reacquired
by invoking <code><phrase role="identifier">lk</phrase><phrase role="special">.</phrase><phrase
role="identifier">lock</phrase><phrase role="special">()</phrase></code>
before the call to <code><phrase role="identifier">wait_until</phrase></code>
returns. The lock is also reacquired by invoking <code><phrase role="identifier">lk</phrase><phrase
role="special">.</phrase><phrase role="identifier">lock</phrase><phrase
role="special">()</phrase></code> if the function exits with an exception.
The member function accepting <code><phrase role="identifier">pred</phrase></code>
is shorthand for:
<programlisting><phrase role="keyword">while</phrase> <phrase role="special">(</phrase> <phrase role="special">!</phrase> <phrase role="identifier">pred</phrase><phrase role="special">()</phrase> <phrase role="special">)</phrase> <phrase role="special">{</phrase>
<phrase role="keyword">if</phrase> <phrase role="special">(</phrase> <phrase role="identifier">cv_status</phrase><phrase role="special">::</phrase><phrase role="identifier">timeout</phrase> <phrase role="special">==</phrase> <phrase role="identifier">wait_until</phrase><phrase role="special">(</phrase> <phrase role="identifier">lk</phrase><phrase role="special">,</phrase> <phrase role="identifier">abs_time</phrase><phrase role="special">)</phrase> <phrase role="special">)</phrase>
<phrase role="keyword">return</phrase> <phrase role="identifier">pred</phrase><phrase role="special">();</phrase>
<phrase role="special">}</phrase>
<phrase role="keyword">return</phrase> <phrase role="keyword">true</phrase><phrase role="special">;</phrase>
</programlisting>
That is, even if <code><phrase role="identifier">wait_until</phrase><phrase
role="special">()</phrase></code> times out, it can still return <code><phrase
role="keyword">true</phrase></code> if <code><phrase role="identifier">pred</phrase><phrase
role="special">()</phrase></code> returns <code><phrase role="keyword">true</phrase></code>
at that time.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>Postcondition:</term>
<listitem>
<para>
<code><phrase role="identifier">lk</phrase></code> is locked by the
current fiber.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>Throws:</term>
<listitem>
<para>
<code><phrase role="identifier">fiber_error</phrase></code> if an error
occurs or timeout-related exceptions.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>Returns:</term>
<listitem>
<para>
The overload without <code><phrase role="identifier">pred</phrase></code>
returns <code><phrase role="identifier">cv_status</phrase><phrase role="special">::</phrase><phrase
role="identifier">no_timeout</phrase></code> if awakened by <code><phrase
role="identifier">notify_one</phrase><phrase role="special">()</phrase></code>
or <code><phrase role="identifier">notify_all</phrase><phrase role="special">()</phrase></code>,
or <code><phrase role="identifier">cv_status</phrase><phrase role="special">::</phrase><phrase
role="identifier">timeout</phrase></code> if awakened because the system
time is past <code><phrase role="identifier">abs_time</phrase></code>.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>Returns:</term>
<listitem>
<para>
The overload accepting <code><phrase role="identifier">pred</phrase></code>
returns <code><phrase role="keyword">false</phrase></code> if the call
is returning because the time specified by <code><phrase role="identifier">abs_time</phrase></code>
was reached and the predicate returns <code><phrase role="keyword">false</phrase></code>,
<code><phrase role="keyword">true</phrase></code> otherwise.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>Note:</term>
<listitem>
<para>
See <emphasis role="bold">Note</emphasis> for <link linkend="condition_variable_wait"><code>condition_variable::wait()</code></link>.
</para>
</listitem>
</varlistentry>
</variablelist>
<para>
<bridgehead renderas="sect4" id="condition_variable_wait_for_bridgehead">
<phrase id="condition_variable_wait_for"/>
<link linkend="condition_variable_wait_for">Templated
member function <code>wait_for</code>()</link>
</bridgehead>
</para>
<programlisting><phrase role="keyword">template</phrase><phrase role="special">&lt;</phrase> typename <phrase role="identifier">Rep</phrase><phrase role="special">,</phrase> <phrase role="keyword">typename</phrase> <phrase role="identifier">Period</phrase> <phrase role="special">&gt;</phrase>
<phrase role="identifier">cv_status</phrase> <phrase role="identifier">wait_for</phrase><phrase role="special">(</phrase> std::unique_lock&lt; mutex &gt; <phrase role="special">&amp;</phrase> <phrase role="identifier">lk</phrase><phrase role="special">,</phrase>
<phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">chrono</phrase><phrase role="special">::</phrase><phrase role="identifier">duration</phrase><phrase role="special">&lt;</phrase> <phrase role="identifier">Rep</phrase><phrase role="special">,</phrase> <phrase role="identifier">Period</phrase> <phrase role="special">&gt;</phrase> <phrase role="keyword">const</phrase><phrase role="special">&amp;</phrase> <phrase role="identifier">rel_time</phrase><phrase role="special">);</phrase>
<phrase role="keyword">template</phrase><phrase role="special">&lt;</phrase> typename <phrase role="identifier">Rep</phrase><phrase role="special">,</phrase> <phrase role="keyword">typename</phrase> <phrase role="identifier">Period</phrase><phrase role="special">,</phrase> <phrase role="keyword">typename</phrase> <phrase role="identifier">Pred</phrase> <phrase role="special">&gt;</phrase>
<phrase role="keyword">bool</phrase> <phrase role="identifier">wait_for</phrase><phrase role="special">(</phrase> std::unique_lock&lt; mutex &gt; <phrase role="special">&amp;</phrase> <phrase role="identifier">lk</phrase><phrase role="special">,</phrase>
<phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">chrono</phrase><phrase role="special">::</phrase><phrase role="identifier">duration</phrase><phrase role="special">&lt;</phrase> <phrase role="identifier">Rep</phrase><phrase role="special">,</phrase> <phrase role="identifier">Period</phrase> <phrase role="special">&gt;</phrase> <phrase role="keyword">const</phrase><phrase role="special">&amp;</phrase> <phrase role="identifier">rel_time</phrase><phrase role="special">,</phrase>
<phrase role="identifier">Pred</phrase> <phrase role="identifier">pred</phrase><phrase role="special">);</phrase>
</programlisting>
<variablelist>
<title></title>
<varlistentry>
<term>Precondition:</term>
<listitem>
<para>
<code><phrase role="identifier">lk</phrase></code> is locked by the
current fiber, and either no other fiber is currently waiting on <code><phrase
role="special">*</phrase><phrase role="keyword">this</phrase></code>,
or the execution of the <code><phrase role="identifier">mutex</phrase><phrase
role="special">()</phrase></code> member function on the <code><phrase
role="identifier">lk</phrase></code> objects supplied in the calls
to <code><phrase role="identifier">wait</phrase></code>, <code><phrase
role="identifier">wait_for</phrase></code> or <code><phrase role="identifier">wait_until</phrase></code>
in all the fibers currently waiting on <code><phrase role="special">*</phrase><phrase
role="keyword">this</phrase></code> would return the same value as
<code><phrase role="identifier">lk</phrase><phrase role="special">.</phrase><phrase
role="identifier">mutex</phrase><phrase role="special">()</phrase></code>
for this call to <code><phrase role="identifier">wait_for</phrase></code>.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>Effects:</term>
<listitem>
<para>
Atomically call <code><phrase role="identifier">lk</phrase><phrase
role="special">.</phrase><phrase role="identifier">unlock</phrase><phrase
role="special">()</phrase></code> and blocks the current fiber. The
fiber will unblock when notified by a call to <code><phrase role="keyword">this</phrase><phrase
role="special">-&gt;</phrase><phrase role="identifier">notify_one</phrase><phrase
role="special">()</phrase></code> or <code><phrase role="keyword">this</phrase><phrase
role="special">-&gt;</phrase><phrase role="identifier">notify_all</phrase><phrase
role="special">()</phrase></code>, when a time interval equal to or
greater than the specified <code><phrase role="identifier">rel_time</phrase></code>
has elapsed. When the fiber is unblocked (for whatever reason), the
lock is reacquired by invoking <code><phrase role="identifier">lk</phrase><phrase
role="special">.</phrase><phrase role="identifier">lock</phrase><phrase
role="special">()</phrase></code> before the call to <code><phrase
role="identifier">wait</phrase></code> returns. The lock is also reacquired
by invoking <code><phrase role="identifier">lk</phrase><phrase role="special">.</phrase><phrase
role="identifier">lock</phrase><phrase role="special">()</phrase></code>
if the function exits with an exception. The <code><phrase role="identifier">wait_for</phrase><phrase
role="special">()</phrase></code> member function accepting <code><phrase
role="identifier">pred</phrase></code> is shorthand for:
<programlisting><phrase role="keyword">while</phrase> <phrase role="special">(</phrase> <phrase role="special">!</phrase> <phrase role="identifier">pred</phrase><phrase role="special">()</phrase> <phrase role="special">)</phrase> <phrase role="special">{</phrase>
<phrase role="keyword">if</phrase> <phrase role="special">(</phrase> <phrase role="identifier">cv_status</phrase><phrase role="special">::</phrase><phrase role="identifier">timeout</phrase> <phrase role="special">==</phrase> <phrase role="identifier">wait_for</phrase><phrase role="special">(</phrase> <phrase role="identifier">lk</phrase><phrase role="special">,</phrase> <phrase role="identifier">rel_time</phrase><phrase role="special">)</phrase> <phrase role="special">)</phrase> <phrase role="special">{</phrase>
<phrase role="keyword">return</phrase> <phrase role="identifier">pred</phrase><phrase role="special">();</phrase>
<phrase role="special">}</phrase>
<phrase role="special">}</phrase>
<phrase role="keyword">return</phrase> <phrase role="keyword">true</phrase><phrase role="special">;</phrase>
</programlisting>
(except of course that <code><phrase role="identifier">rel_time</phrase></code>
is adjusted for each iteration). The point is that, even if <code><phrase
role="identifier">wait_for</phrase><phrase role="special">()</phrase></code>
times out, it can still return <code><phrase role="keyword">true</phrase></code>
if <code><phrase role="identifier">pred</phrase><phrase role="special">()</phrase></code>
returns <code><phrase role="keyword">true</phrase></code> at that time.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>Postcondition:</term>
<listitem>
<para>
<code><phrase role="identifier">lk</phrase></code> is locked by the
current fiber.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>Throws:</term>
<listitem>
<para>
<code><phrase role="identifier">fiber_error</phrase></code> if an error
occurs or timeout-related exceptions.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>Returns:</term>
<listitem>
<para>
The overload without <code><phrase role="identifier">pred</phrase></code>
returns <code><phrase role="identifier">cv_status</phrase><phrase role="special">::</phrase><phrase
role="identifier">no_timeout</phrase></code> if awakened by <code><phrase
role="identifier">notify_one</phrase><phrase role="special">()</phrase></code>
or <code><phrase role="identifier">notify_all</phrase><phrase role="special">()</phrase></code>,
or <code><phrase role="identifier">cv_status</phrase><phrase role="special">::</phrase><phrase
role="identifier">timeout</phrase></code> if awakened because at least
<code><phrase role="identifier">rel_time</phrase></code> has elapsed.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>Returns:</term>
<listitem>
<para>
The overload accepting <code><phrase role="identifier">pred</phrase></code>
returns <code><phrase role="keyword">false</phrase></code> if the call
is returning because at least <code><phrase role="identifier">rel_time</phrase></code>
has elapsed and the predicate returns <code><phrase role="keyword">false</phrase></code>,
<code><phrase role="keyword">true</phrase></code> otherwise.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>Note:</term>
<listitem>
<para>
See <emphasis role="bold">Note</emphasis> for <link linkend="condition_variable_wait"><code>condition_variable::wait()</code></link>.
</para>
</listitem>
</varlistentry>
</variablelist>
</section>
<section id="fiber.synchronization.barriers">
<title><link linkend="fiber.synchronization.barriers">Barriers</link></title>
<para>
A barrier is a concept also known as a <emphasis>rendezvous</emphasis>, it
is a synchronization point between multiple contexts of execution (fibers).
The barrier is configured for a particular number of fibers (<code><phrase
role="identifier">n</phrase></code>), and as fibers reach the barrier they
must wait until all <code><phrase role="identifier">n</phrase></code> fibers
have arrived. Once the <code><phrase role="identifier">n</phrase></code>-th
fiber has reached the barrier, all the waiting fibers can proceed, and the
barrier is reset.
</para>
<para>
The fact that the barrier automatically resets is significant. Consider a
case in which you launch some number of fibers and want to wait only until
the first of them has completed. You might be tempted to use a <code><phrase
role="identifier">barrier</phrase><phrase role="special">(</phrase><phrase
role="number">2</phrase><phrase role="special">)</phrase></code> as the synchronization
mechanism, making each new fiber call its <link linkend="barrier_wait"><code>barrier::wait()</code></link> method,
then calling <code><phrase role="identifier">wait</phrase><phrase role="special">()</phrase></code>
in the launching fiber to wait until the first other fiber completes.
</para>
<para>
That will in fact unblock the launching fiber. The unfortunate part is that
it will continue blocking the <emphasis>remaining</emphasis> fibers.
</para>
<para>
Consider the following scenario:
</para>
<orderedlist>
<listitem>
<simpara>
Fiber <quote>main</quote> launches fibers A, B, C and D, then calls
<code><phrase role="identifier">barrier</phrase><phrase role="special">::</phrase><phrase
role="identifier">wait</phrase><phrase role="special">()</phrase></code>.
</simpara>
</listitem>
<listitem>
<simpara>
Fiber C finishes first and likewise calls <code><phrase role="identifier">barrier</phrase><phrase
role="special">::</phrase><phrase role="identifier">wait</phrase><phrase
role="special">()</phrase></code>.
</simpara>
</listitem>
<listitem>
<simpara>
Fiber <quote>main</quote> is unblocked, as desired.
</simpara>
</listitem>
<listitem>
<simpara>
Fiber B calls <code><phrase role="identifier">barrier</phrase><phrase
role="special">::</phrase><phrase role="identifier">wait</phrase><phrase
role="special">()</phrase></code>. Fiber B is <emphasis>blocked!</emphasis>
</simpara>
</listitem>
<listitem>
<simpara>
Fiber A calls <code><phrase role="identifier">barrier</phrase><phrase
role="special">::</phrase><phrase role="identifier">wait</phrase><phrase
role="special">()</phrase></code>. Fibers A and B are unblocked.
</simpara>
</listitem>
<listitem>
<simpara>
Fiber D calls <code><phrase role="identifier">barrier</phrase><phrase
role="special">::</phrase><phrase role="identifier">wait</phrase><phrase
role="special">()</phrase></code>. Fiber D is blocked indefinitely.
</simpara>
</listitem>
</orderedlist>
<para>
(See also <link linkend="wait_first_simple_section">when_any, simple completion</link>.)
</para>
<note>
<para>
It is unwise to tie the lifespan of a barrier to any one of its participating
fibers. Although conceptually all waiting fibers awaken <quote>simultaneously,</quote>
because of the nature of fibers, in practice they will awaken one by one
in indeterminate order.<footnote id="fiber.synchronization.barriers.f0">
<para>
The current implementation wakes fibers in FIFO order: the first to call
<code><phrase role="identifier">wait</phrase><phrase role="special">()</phrase></code>
wakes first, and so forth. But it is perilous to rely on the order in
which the various fibers will reach the <code><phrase role="identifier">wait</phrase><phrase
role="special">()</phrase></code> call.
</para>
</footnote> The rest of the waiting fibers will still be blocked in <code><phrase
role="identifier">wait</phrase><phrase role="special">()</phrase></code>,
which must, before returning, access data members in the barrier object.
</para>
</note>
<para>
<bridgehead renderas="sect4" id="class_barrier_bridgehead">
<phrase id="class_barrier"/>
<link linkend="class_barrier">Class <code>barrier</code></link>
</bridgehead>
</para>
<programlisting><phrase role="preprocessor">#include</phrase> <phrase role="special">&lt;</phrase><phrase role="identifier">boost</phrase><phrase role="special">/</phrase><phrase role="identifier">fiber</phrase><phrase role="special">/</phrase><phrase role="identifier">barrier</phrase><phrase role="special">.</phrase><phrase role="identifier">hpp</phrase><phrase role="special">&gt;</phrase>
<phrase role="keyword">namespace</phrase> <phrase role="identifier">boost</phrase> <phrase role="special">{</phrase>
<phrase role="keyword">namespace</phrase> <phrase role="identifier">fibers</phrase> <phrase role="special">{</phrase>
<phrase role="keyword">class</phrase> <phrase role="identifier">barrier</phrase> <phrase role="special">{</phrase>
<phrase role="keyword">public</phrase><phrase role="special">:</phrase>
<phrase role="keyword">explicit</phrase> <phrase role="identifier">barrier</phrase><phrase role="special">(</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">size_t</phrase><phrase role="special">);</phrase>
<phrase role="identifier">barrier</phrase><phrase role="special">(</phrase> <phrase role="identifier">barrier</phrase> <phrase role="keyword">const</phrase><phrase role="special">&amp;)</phrase> <phrase role="special">=</phrase> <phrase role="keyword">delete</phrase><phrase role="special">;</phrase>
<phrase role="identifier">barrier</phrase> <phrase role="special">&amp;</phrase> <phrase role="keyword">operator</phrase><phrase role="special">=(</phrase> <phrase role="identifier">barrier</phrase> <phrase role="keyword">const</phrase><phrase role="special">&amp;)</phrase> <phrase role="special">=</phrase> <phrase role="keyword">delete</phrase><phrase role="special">;</phrase>
<phrase role="keyword">bool</phrase> <phrase role="identifier">wait</phrase><phrase role="special">();</phrase>
<phrase role="special">};</phrase>
<phrase role="special">}}</phrase>
</programlisting>
<para>
Instances of <link linkend="class_barrier"><code>barrier</code></link> are not copyable or movable.
</para>
<bridgehead renderas="sect4" id="fiber.synchronization.barriers.h0">
<phrase id="fiber.synchronization.barriers.constructor"/><link linkend="fiber.synchronization.barriers.constructor">Constructor</link>
</bridgehead>
<programlisting><phrase role="keyword">explicit</phrase> <phrase role="identifier">barrier</phrase><phrase role="special">(</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">size_t</phrase> <phrase role="identifier">initial</phrase><phrase role="special">);</phrase>
</programlisting>
<variablelist>
<title></title>
<varlistentry>
<term>Effects:</term>
<listitem>
<para>
Construct a barrier for <code><phrase role="identifier">initial</phrase></code>
fibers.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>Throws:</term>
<listitem>
<para>
<code><phrase role="identifier">fiber_error</phrase></code>
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>Error Conditions:</term>
<listitem>
<para>
<emphasis role="bold">invalid_argument</emphasis>: if <code><phrase
role="identifier">initial</phrase></code> is zero.
</para>
</listitem>
</varlistentry>
</variablelist>
<para>
<bridgehead renderas="sect4" id="barrier_wait_bridgehead">
<phrase id="barrier_wait"/>
<link linkend="barrier_wait">Member function <code>wait</code>()</link>
</bridgehead>
</para>
<programlisting><phrase role="keyword">bool</phrase> <phrase role="identifier">wait</phrase><phrase role="special">();</phrase>
</programlisting>
<variablelist>
<title></title>
<varlistentry>
<term>Effects:</term>
<listitem>
<para>
Block until <code><phrase role="identifier">initial</phrase></code>
fibers have called <code><phrase role="identifier">wait</phrase></code>
on <code><phrase role="special">*</phrase><phrase role="keyword">this</phrase></code>.
When the <code><phrase role="identifier">initial</phrase></code>-th
fiber calls <code><phrase role="identifier">wait</phrase></code>, all
waiting fibers are unblocked, and the barrier is reset.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>Returns:</term>
<listitem>
<para>
<code><phrase role="keyword">true</phrase></code> for exactly one fiber
from each batch of waiting fibers, <code><phrase role="keyword">false</phrase></code>
otherwise.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>Throws:</term>
<listitem>
<para>
<code><phrase role="identifier">fiber_error</phrase></code>
</para>
</listitem>
</varlistentry>
</variablelist>
</section>
<section id="fiber.synchronization.channels">
<title><link linkend="fiber.synchronization.channels">Channels</link></title>
<para>
A channel is a model to communicate and synchronize <code><phrase role="identifier">Threads</phrase>
<phrase role="identifier">of</phrase> <phrase role="identifier">Execution</phrase></code>
<footnote id="fiber.synchronization.channels.f0">
<para>
The smallest ordered sequence of instructions that can be managed independently
by a scheduler is called a <code><phrase role="identifier">Thread</phrase>
<phrase role="identifier">of</phrase> <phrase role="identifier">Execution</phrase></code>.
</para>
</footnote> via message passing.
</para>
<anchor id="class_channel_op_status"/>
<bridgehead renderas="sect4" id="fiber.synchronization.channels.h0">
<phrase id="fiber.synchronization.channels.enumeration__code__phrase_role__identifier__channel_op_status__phrase___code_"/><link
linkend="fiber.synchronization.channels.enumeration__code__phrase_role__identifier__channel_op_status__phrase___code_">Enumeration
<code><phrase role="identifier">channel_op_status</phrase></code></link>
</bridgehead>
<para>
channel operations return the state of the channel.
</para>
<programlisting><phrase role="keyword">enum</phrase> <phrase role="keyword">class</phrase> <phrase role="identifier">channel_op_status</phrase> <phrase role="special">{</phrase>
<phrase role="identifier">success</phrase><phrase role="special">,</phrase>
<phrase role="identifier">empty</phrase><phrase role="special">,</phrase>
<phrase role="identifier">full</phrase><phrase role="special">,</phrase>
<phrase role="identifier">closed</phrase><phrase role="special">,</phrase>
<phrase role="identifier">timeout</phrase>
<phrase role="special">};</phrase>
</programlisting>
<bridgehead renderas="sect4" id="fiber.synchronization.channels.h1">
<phrase id="fiber.synchronization.channels._code__phrase_role__identifier__success__phrase___code_"/><link
linkend="fiber.synchronization.channels._code__phrase_role__identifier__success__phrase___code_"><code><phrase
role="identifier">success</phrase></code></link>
</bridgehead>
<variablelist>
<title></title>
<varlistentry>
<term>Effects:</term>
<listitem>
<para>
Operation was successful.
</para>
</listitem>
</varlistentry>
</variablelist>
<bridgehead renderas="sect4" id="fiber.synchronization.channels.h2">
<phrase id="fiber.synchronization.channels._code__phrase_role__identifier__empty__phrase___code_"/><link
linkend="fiber.synchronization.channels._code__phrase_role__identifier__empty__phrase___code_"><code><phrase
role="identifier">empty</phrase></code></link>
</bridgehead>
<variablelist>
<title></title>
<varlistentry>
<term>Effects:</term>
<listitem>
<para>
channel is empty, operation failed.
</para>
</listitem>
</varlistentry>
</variablelist>
<bridgehead renderas="sect4" id="fiber.synchronization.channels.h3">
<phrase id="fiber.synchronization.channels._code__phrase_role__identifier__full__phrase___code_"/><link
linkend="fiber.synchronization.channels._code__phrase_role__identifier__full__phrase___code_"><code><phrase
role="identifier">full</phrase></code></link>
</bridgehead>
<variablelist>
<title></title>
<varlistentry>
<term>Effects:</term>
<listitem>
<para>
channel is full, operation failed.
</para>
</listitem>
</varlistentry>
</variablelist>
<bridgehead renderas="sect4" id="fiber.synchronization.channels.h4">
<phrase id="fiber.synchronization.channels._code__phrase_role__identifier__closed__phrase___code_"/><link
linkend="fiber.synchronization.channels._code__phrase_role__identifier__closed__phrase___code_"><code><phrase
role="identifier">closed</phrase></code></link>
</bridgehead>
<variablelist>
<title></title>
<varlistentry>
<term>Effects:</term>
<listitem>
<para>
channel is closed, operation failed.
</para>
</listitem>
</varlistentry>
</variablelist>
<bridgehead renderas="sect4" id="fiber.synchronization.channels.h5">
<phrase id="fiber.synchronization.channels._code__phrase_role__identifier__timeout__phrase___code_"/><link
linkend="fiber.synchronization.channels._code__phrase_role__identifier__timeout__phrase___code_"><code><phrase
role="identifier">timeout</phrase></code></link>
</bridgehead>
<variablelist>
<title></title>
<varlistentry>
<term>Effects:</term>
<listitem>
<para>
The operation did not become ready before specified timeout elapsed.
</para>
</listitem>
</varlistentry>
</variablelist>
<section id="fiber.synchronization.channels.buffered_channel">
<title><link linkend="fiber.synchronization.channels.buffered_channel">Buffered
Channel</link></title>
<para>
<emphasis role="bold">Boost.Fiber</emphasis> provides a bounded, buffered
channel (MPMC queue) suitable to synchonize fibers (running on same or
different threads) via asynchronouss message passing.
</para>
<programlisting><phrase role="keyword">typedef</phrase> <phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">fibers</phrase><phrase role="special">::</phrase><phrase role="identifier">buffered_channel</phrase><phrase role="special">&lt;</phrase> <phrase role="keyword">int</phrase> <phrase role="special">&gt;</phrase> <phrase role="identifier">channel_t</phrase><phrase role="special">;</phrase>
<phrase role="keyword">void</phrase> <phrase role="identifier">send</phrase><phrase role="special">(</phrase> <phrase role="identifier">channel_t</phrase> <phrase role="special">&amp;</phrase> <phrase role="identifier">chan</phrase><phrase role="special">)</phrase> <phrase role="special">{</phrase>
<phrase role="keyword">for</phrase> <phrase role="special">(</phrase> <phrase role="keyword">int</phrase> <phrase role="identifier">i</phrase> <phrase role="special">=</phrase> <phrase role="number">0</phrase><phrase role="special">;</phrase> <phrase role="identifier">i</phrase> <phrase role="special">&lt;</phrase> <phrase role="number">5</phrase><phrase role="special">;</phrase> <phrase role="special">++</phrase><phrase role="identifier">i</phrase><phrase role="special">)</phrase> <phrase role="special">{</phrase>
<phrase role="identifier">chan</phrase><phrase role="special">.</phrase><phrase role="identifier">push</phrase><phrase role="special">(</phrase> <phrase role="identifier">i</phrase><phrase role="special">);</phrase>
<phrase role="special">}</phrase>
<phrase role="identifier">chan</phrase><phrase role="special">.</phrase><phrase role="identifier">close</phrase><phrase role="special">();</phrase>
<phrase role="special">}</phrase>
<phrase role="keyword">void</phrase> <phrase role="identifier">recv</phrase><phrase role="special">(</phrase> <phrase role="identifier">channel_t</phrase> <phrase role="special">&amp;</phrase> <phrase role="identifier">chan</phrase><phrase role="special">)</phrase> <phrase role="special">{</phrase>
<phrase role="keyword">int</phrase> <phrase role="identifier">i</phrase><phrase role="special">;</phrase>
<phrase role="keyword">while</phrase> <phrase role="special">(</phrase> <phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">fibers</phrase><phrase role="special">::</phrase><phrase role="identifier">channel_op_status</phrase><phrase role="special">::</phrase><phrase role="identifier">success</phrase> <phrase role="special">==</phrase> <phrase role="identifier">chan</phrase><phrase role="special">.</phrase><phrase role="identifier">pop</phrase><phrase role="special">(</phrase><phrase role="identifier">i</phrase><phrase role="special">)</phrase> <phrase role="special">)</phrase> <phrase role="special">{</phrase>
<phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">cout</phrase> <phrase role="special">&lt;&lt;</phrase> <phrase role="string">&quot;received &quot;</phrase> <phrase role="special">&lt;&lt;</phrase> <phrase role="identifier">i</phrase> <phrase role="special">&lt;&lt;</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">endl</phrase><phrase role="special">;</phrase>
<phrase role="special">}</phrase>
<phrase role="special">}</phrase>
<phrase role="identifier">channel_t</phrase> <phrase role="identifier">chan</phrase><phrase role="special">{</phrase> <phrase role="number">2</phrase> <phrase role="special">};</phrase>
<phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">fibers</phrase><phrase role="special">::</phrase><phrase role="identifier">fiber</phrase> <phrase role="identifier">f1</phrase><phrase role="special">(</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">bind</phrase><phrase role="special">(</phrase> <phrase role="identifier">send</phrase><phrase role="special">,</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">ref</phrase><phrase role="special">(</phrase> <phrase role="identifier">chan</phrase><phrase role="special">)</phrase> <phrase role="special">)</phrase> <phrase role="special">);</phrase>
<phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">fibers</phrase><phrase role="special">::</phrase><phrase role="identifier">fiber</phrase> <phrase role="identifier">f2</phrase><phrase role="special">(</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">bind</phrase><phrase role="special">(</phrase> <phrase role="identifier">recv</phrase><phrase role="special">,</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">ref</phrase><phrase role="special">(</phrase> <phrase role="identifier">chan</phrase><phrase role="special">)</phrase> <phrase role="special">)</phrase> <phrase role="special">);</phrase>
<phrase role="identifier">f1</phrase><phrase role="special">.</phrase><phrase role="identifier">join</phrase><phrase role="special">();</phrase>
<phrase role="identifier">f2</phrase><phrase role="special">.</phrase><phrase role="identifier">join</phrase><phrase role="special">();</phrase>
</programlisting>
<para>
Class <code><phrase role="identifier">buffered_channel</phrase></code>
supports range-for syntax:
</para>
<programlisting><phrase role="keyword">typedef</phrase> <phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">fibers</phrase><phrase role="special">::</phrase><phrase role="identifier">buffered_channel</phrase><phrase role="special">&lt;</phrase> <phrase role="keyword">int</phrase> <phrase role="special">&gt;</phrase> <phrase role="identifier">channel_t</phrase><phrase role="special">;</phrase>
<phrase role="keyword">void</phrase> <phrase role="identifier">foo</phrase><phrase role="special">(</phrase> <phrase role="identifier">channel_t</phrase> <phrase role="special">&amp;</phrase> <phrase role="identifier">chan</phrase><phrase role="special">)</phrase> <phrase role="special">{</phrase>
<phrase role="identifier">chan</phrase><phrase role="special">.</phrase><phrase role="identifier">push</phrase><phrase role="special">(</phrase> <phrase role="number">1</phrase><phrase role="special">);</phrase>
<phrase role="identifier">chan</phrase><phrase role="special">.</phrase><phrase role="identifier">push</phrase><phrase role="special">(</phrase> <phrase role="number">1</phrase><phrase role="special">);</phrase>
<phrase role="identifier">chan</phrase><phrase role="special">.</phrase><phrase role="identifier">push</phrase><phrase role="special">(</phrase> <phrase role="number">2</phrase><phrase role="special">);</phrase>
<phrase role="identifier">chan</phrase><phrase role="special">.</phrase><phrase role="identifier">push</phrase><phrase role="special">(</phrase> <phrase role="number">3</phrase><phrase role="special">);</phrase>
<phrase role="identifier">chan</phrase><phrase role="special">.</phrase><phrase role="identifier">push</phrase><phrase role="special">(</phrase> <phrase role="number">5</phrase><phrase role="special">);</phrase>
<phrase role="identifier">chan</phrase><phrase role="special">.</phrase><phrase role="identifier">push</phrase><phrase role="special">(</phrase> <phrase role="number">8</phrase><phrase role="special">);</phrase>
<phrase role="identifier">chan</phrase><phrase role="special">.</phrase><phrase role="identifier">push</phrase><phrase role="special">(</phrase> <phrase role="number">12</phrase><phrase role="special">);</phrase>
<phrase role="identifier">chan</phrase><phrase role="special">.</phrase><phrase role="identifier">close</phrase><phrase role="special">();</phrase>
<phrase role="special">}</phrase>
<phrase role="keyword">void</phrase> <phrase role="identifier">bar</phrase><phrase role="special">(</phrase> <phrase role="identifier">channel_t</phrase> <phrase role="special">&amp;</phrase> <phrase role="identifier">chan</phrase><phrase role="special">)</phrase> <phrase role="special">{</phrase>
<phrase role="keyword">for</phrase> <phrase role="special">(</phrase> <phrase role="keyword">unsigned</phrase> <phrase role="keyword">int</phrase> <phrase role="identifier">value</phrase> <phrase role="special">:</phrase> <phrase role="identifier">chan</phrase><phrase role="special">)</phrase> <phrase role="special">{</phrase>
<phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">cout</phrase> <phrase role="special">&lt;&lt;</phrase> <phrase role="identifier">value</phrase> <phrase role="special">&lt;&lt;</phrase> <phrase role="string">&quot; &quot;</phrase><phrase role="special">;</phrase>
<phrase role="special">}</phrase>
<phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">cout</phrase> <phrase role="special">&lt;&lt;</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">endl</phrase><phrase role="special">;</phrase>
<phrase role="special">}</phrase>
</programlisting>
<para>
<bridgehead renderas="sect4" id="class_buffered_channel_bridgehead">
<phrase id="class_buffered_channel"/>
<link linkend="class_buffered_channel">Template
<code>buffered_channel&lt;&gt;</code></link>
</bridgehead>
</para>
<programlisting><phrase role="preprocessor">#include</phrase> <phrase role="special">&lt;</phrase><phrase role="identifier">boost</phrase><phrase role="special">/</phrase><phrase role="identifier">fiber</phrase><phrase role="special">/</phrase><phrase role="identifier">buffered_channel</phrase><phrase role="special">.</phrase><phrase role="identifier">hpp</phrase><phrase role="special">&gt;</phrase>
<phrase role="keyword">namespace</phrase> <phrase role="identifier">boost</phrase> <phrase role="special">{</phrase>
<phrase role="keyword">namespace</phrase> <phrase role="identifier">fibers</phrase> <phrase role="special">{</phrase>
<phrase role="keyword">template</phrase><phrase role="special">&lt;</phrase> <phrase role="keyword">typename</phrase> <phrase role="identifier">T</phrase> <phrase role="special">&gt;</phrase>
<phrase role="keyword">class</phrase> <phrase role="identifier">buffered_channel</phrase> <phrase role="special">{</phrase>
<phrase role="keyword">public</phrase><phrase role="special">:</phrase>
<phrase role="keyword">typedef</phrase> <phrase role="identifier">T</phrase> <phrase role="identifier">value_type</phrase><phrase role="special">;</phrase>
<phrase role="keyword">class</phrase> <phrase role="identifier">iterator</phrase><phrase role="special">;</phrase>
<phrase role="keyword">explicit</phrase> <phrase role="identifier">buffered_channel</phrase><phrase role="special">(</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">size_t</phrase> <phrase role="identifier">capacity</phrase><phrase role="special">);</phrase>
<phrase role="identifier">buffered_channel</phrase><phrase role="special">(</phrase> <phrase role="identifier">buffered_channel</phrase> <phrase role="keyword">const</phrase><phrase role="special">&amp;</phrase> <phrase role="identifier">other</phrase><phrase role="special">)</phrase> <phrase role="special">=</phrase> <phrase role="keyword">delete</phrase><phrase role="special">;</phrase>
<phrase role="identifier">buffered_channel</phrase> <phrase role="special">&amp;</phrase> <phrase role="keyword">operator</phrase><phrase role="special">=(</phrase> <phrase role="identifier">buffered_channel</phrase> <phrase role="keyword">const</phrase><phrase role="special">&amp;</phrase> <phrase role="identifier">other</phrase><phrase role="special">)</phrase> <phrase role="special">=</phrase> <phrase role="keyword">delete</phrase><phrase role="special">;</phrase>
<phrase role="keyword">void</phrase> <phrase role="identifier">close</phrase><phrase role="special">()</phrase> <phrase role="keyword">noexcept</phrase><phrase role="special">;</phrase>
<phrase role="identifier">channel_op_status</phrase> <phrase role="identifier">push</phrase><phrase role="special">(</phrase> <phrase role="identifier">value_type</phrase> <phrase role="keyword">const</phrase><phrase role="special">&amp;</phrase> <phrase role="identifier">va</phrase><phrase role="special">);</phrase>
<phrase role="identifier">channel_op_status</phrase> <phrase role="identifier">push</phrase><phrase role="special">(</phrase> <phrase role="identifier">value_type</phrase> <phrase role="special">&amp;&amp;</phrase> <phrase role="identifier">va</phrase><phrase role="special">);</phrase>
<phrase role="keyword">template</phrase><phrase role="special">&lt;</phrase> <phrase role="keyword">typename</phrase> <phrase role="identifier">Rep</phrase><phrase role="special">,</phrase> <phrase role="keyword">typename</phrase> <phrase role="identifier">Period</phrase> <phrase role="special">&gt;</phrase>
<phrase role="identifier">channel_op_status</phrase> <phrase role="identifier">push_wait_for</phrase><phrase role="special">(</phrase>
<phrase role="identifier">value_type</phrase> <phrase role="keyword">const</phrase><phrase role="special">&amp;</phrase> <phrase role="identifier">va</phrase><phrase role="special">,</phrase>
<phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">chrono</phrase><phrase role="special">::</phrase><phrase role="identifier">duration</phrase><phrase role="special">&lt;</phrase> <phrase role="identifier">Rep</phrase><phrase role="special">,</phrase> <phrase role="identifier">Period</phrase> <phrase role="special">&gt;</phrase> <phrase role="keyword">const</phrase><phrase role="special">&amp;</phrase> <phrase role="identifier">timeout_duration</phrase><phrase role="special">);</phrase>
<phrase role="identifier">channel_op_status</phrase> <phrase role="identifier">push_wait_for</phrase><phrase role="special">(</phrase> <phrase role="identifier">value_type</phrase> <phrase role="special">&amp;&amp;</phrase> <phrase role="identifier">va</phrase><phrase role="special">,</phrase>
<phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">chrono</phrase><phrase role="special">::</phrase><phrase role="identifier">duration</phrase><phrase role="special">&lt;</phrase> <phrase role="identifier">Rep</phrase><phrase role="special">,</phrase> <phrase role="identifier">Period</phrase> <phrase role="special">&gt;</phrase> <phrase role="keyword">const</phrase><phrase role="special">&amp;</phrase> <phrase role="identifier">timeout_duration</phrase><phrase role="special">);</phrase>
<phrase role="keyword">template</phrase><phrase role="special">&lt;</phrase> <phrase role="keyword">typename</phrase> <phrase role="identifier">Clock</phrase><phrase role="special">,</phrase> <phrase role="keyword">typename</phrase> <phrase role="identifier">Duration</phrase> <phrase role="special">&gt;</phrase>
<phrase role="identifier">channel_op_status</phrase> <phrase role="identifier">push_wait_until</phrase><phrase role="special">(</phrase>
<phrase role="identifier">value_type</phrase> <phrase role="keyword">const</phrase><phrase role="special">&amp;</phrase> <phrase role="identifier">va</phrase><phrase role="special">,</phrase>
<phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">chrono</phrase><phrase role="special">::</phrase><phrase role="identifier">time_point</phrase><phrase role="special">&lt;</phrase> <phrase role="identifier">Clock</phrase><phrase role="special">,</phrase> <phrase role="identifier">Duration</phrase> <phrase role="special">&gt;</phrase> <phrase role="keyword">const</phrase><phrase role="special">&amp;</phrase> <phrase role="identifier">timeout_time</phrase><phrase role="special">);</phrase>
<phrase role="keyword">template</phrase><phrase role="special">&lt;</phrase> <phrase role="keyword">typename</phrase> <phrase role="identifier">Clock</phrase><phrase role="special">,</phrase> <phrase role="keyword">typename</phrase> <phrase role="identifier">Duration</phrase> <phrase role="special">&gt;</phrase>
<phrase role="identifier">channel_op_status</phrase> <phrase role="identifier">push_wait_until</phrase><phrase role="special">(</phrase>
<phrase role="identifier">value_type</phrase> <phrase role="special">&amp;&amp;</phrase> <phrase role="identifier">va</phrase><phrase role="special">,</phrase>
<phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">chrono</phrase><phrase role="special">::</phrase><phrase role="identifier">time_point</phrase><phrase role="special">&lt;</phrase> <phrase role="identifier">Clock</phrase><phrase role="special">,</phrase> <phrase role="identifier">Duration</phrase> <phrase role="special">&gt;</phrase> <phrase role="keyword">const</phrase><phrase role="special">&amp;</phrase> <phrase role="identifier">timeout_time</phrase><phrase role="special">);</phrase>
<phrase role="identifier">channel_op_status</phrase> <phrase role="identifier">try_push</phrase><phrase role="special">(</phrase> <phrase role="identifier">value_type</phrase> <phrase role="keyword">const</phrase><phrase role="special">&amp;</phrase> <phrase role="identifier">va</phrase><phrase role="special">);</phrase>
<phrase role="identifier">channel_op_status</phrase> <phrase role="identifier">try_push</phrase><phrase role="special">(</phrase> <phrase role="identifier">value_type</phrase> <phrase role="special">&amp;&amp;</phrase> <phrase role="identifier">va</phrase><phrase role="special">);</phrase>
<phrase role="identifier">channel_op_status</phrase> <phrase role="identifier">pop</phrase><phrase role="special">(</phrase> <phrase role="identifier">value_type</phrase> <phrase role="special">&amp;</phrase> <phrase role="identifier">va</phrase><phrase role="special">);</phrase>
<phrase role="identifier">value_type</phrase> <phrase role="identifier">value_pop</phrase><phrase role="special">();</phrase>
<phrase role="keyword">template</phrase><phrase role="special">&lt;</phrase> <phrase role="keyword">typename</phrase> <phrase role="identifier">Rep</phrase><phrase role="special">,</phrase> <phrase role="keyword">typename</phrase> <phrase role="identifier">Period</phrase> <phrase role="special">&gt;</phrase>
<phrase role="identifier">channel_op_status</phrase> <phrase role="identifier">pop_wait_for</phrase><phrase role="special">(</phrase>
<phrase role="identifier">value_type</phrase> <phrase role="special">&amp;</phrase> <phrase role="identifier">va</phrase><phrase role="special">,</phrase>
<phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">chrono</phrase><phrase role="special">::</phrase><phrase role="identifier">duration</phrase><phrase role="special">&lt;</phrase> <phrase role="identifier">Rep</phrase><phrase role="special">,</phrase> <phrase role="identifier">Period</phrase> <phrase role="special">&gt;</phrase> <phrase role="keyword">const</phrase><phrase role="special">&amp;</phrase> <phrase role="identifier">timeout_duration</phrase><phrase role="special">);</phrase>
<phrase role="keyword">template</phrase><phrase role="special">&lt;</phrase> <phrase role="keyword">typename</phrase> <phrase role="identifier">Clock</phrase><phrase role="special">,</phrase> <phrase role="keyword">typename</phrase> <phrase role="identifier">Duration</phrase> <phrase role="special">&gt;</phrase>
<phrase role="identifier">channel_op_status</phrase> <phrase role="identifier">pop_wait_until</phrase><phrase role="special">(</phrase>
<phrase role="identifier">value_type</phrase> <phrase role="special">&amp;</phrase> <phrase role="identifier">va</phrase><phrase role="special">,</phrase>
<phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">chrono</phrase><phrase role="special">::</phrase><phrase role="identifier">time_point</phrase><phrase role="special">&lt;</phrase> <phrase role="identifier">Clock</phrase><phrase role="special">,</phrase> <phrase role="identifier">Duration</phrase> <phrase role="special">&gt;</phrase> <phrase role="keyword">const</phrase><phrase role="special">&amp;</phrase> <phrase role="identifier">timeout_time</phrase><phrase role="special">);</phrase>
<phrase role="identifier">channel_op_status</phrase> <phrase role="identifier">try_pop</phrase><phrase role="special">(</phrase> <phrase role="identifier">value_type</phrase> <phrase role="special">&amp;</phrase> <phrase role="identifier">va</phrase><phrase role="special">);</phrase>
<phrase role="special">};</phrase>
<phrase role="keyword">template</phrase><phrase role="special">&lt;</phrase> <phrase role="keyword">typename</phrase> <phrase role="identifier">T</phrase> <phrase role="special">&gt;</phrase>
<phrase role="identifier">buffered_channel</phrase><phrase role="special">&lt;</phrase> <phrase role="identifier">T</phrase> <phrase role="special">&gt;::</phrase><phrase role="identifier">iterator</phrase> <phrase role="identifier">begin</phrase><phrase role="special">(</phrase> <phrase role="identifier">buffered_channel</phrase><phrase role="special">&lt;</phrase> <phrase role="identifier">T</phrase> <phrase role="special">&gt;</phrase> <phrase role="special">&amp;</phrase> <phrase role="identifier">chan</phrase><phrase role="special">);</phrase>
<phrase role="keyword">template</phrase><phrase role="special">&lt;</phrase> <phrase role="keyword">typename</phrase> <phrase role="identifier">T</phrase> <phrase role="special">&gt;</phrase>
<phrase role="identifier">buffered_channel</phrase><phrase role="special">&lt;</phrase> <phrase role="identifier">T</phrase> <phrase role="special">&gt;::</phrase><phrase role="identifier">iterator</phrase> <phrase role="identifier">end</phrase><phrase role="special">(</phrase> <phrase role="identifier">buffered_channel</phrase><phrase role="special">&lt;</phrase> <phrase role="identifier">T</phrase> <phrase role="special">&gt;</phrase> <phrase role="special">&amp;</phrase> <phrase role="identifier">chan</phrase><phrase role="special">);</phrase>
<phrase role="special">}}</phrase>
</programlisting>
<bridgehead renderas="sect5" id="fiber.synchronization.channels.buffered_channel.h0">
<phrase id="fiber.synchronization.channels.buffered_channel.constructor"/><link
linkend="fiber.synchronization.channels.buffered_channel.constructor">Constructor</link>
</bridgehead>
<programlisting><phrase role="keyword">explicit</phrase> <phrase role="identifier">buffered_channel</phrase><phrase role="special">(</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">size_t</phrase> <phrase role="identifier">capacity</phrase><phrase role="special">);</phrase>
</programlisting>
<variablelist>
<title></title>
<varlistentry>
<term>Preconditions:</term>
<listitem>
<para>
<code><phrase role="number">2</phrase><phrase role="special">&lt;=</phrase><phrase
role="identifier">capacity</phrase> <phrase role="special">&amp;&amp;</phrase>
<phrase role="number">0</phrase><phrase role="special">==(</phrase><phrase
role="identifier">capacity</phrase> <phrase role="special">&amp;</phrase>
<phrase role="special">(</phrase><phrase role="identifier">capacity</phrase><phrase
role="special">-</phrase><phrase role="number">1</phrase><phrase
role="special">))</phrase></code>
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>Effects:</term>
<listitem>
<para>
The constructor constructs an object of class <code><phrase role="identifier">buffered_channel</phrase></code>
with an internal buffer of size <code><phrase role="identifier">capacity</phrase></code>.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>Throws:</term>
<listitem>
<para>
<code><phrase role="identifier">fiber_error</phrase></code>
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>Error Conditions:</term>
<listitem>
<para>
<emphasis role="bold">invalid_argument</emphasis>: if <code><phrase
role="number">0</phrase><phrase role="special">==</phrase><phrase
role="identifier">capacity</phrase> <phrase role="special">||</phrase>
<phrase role="number">0</phrase><phrase role="special">!=(</phrase><phrase
role="identifier">capacity</phrase> <phrase role="special">&amp;</phrase>
<phrase role="special">(</phrase><phrase role="identifier">capacity</phrase><phrase
role="special">-</phrase><phrase role="number">1</phrase><phrase
role="special">))</phrase></code>.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>Notes:</term>
<listitem>
<para>
A <code><phrase role="identifier">push</phrase><phrase role="special">()</phrase></code>,
<code><phrase role="identifier">push_wait_for</phrase><phrase role="special">()</phrase></code>
or <code><phrase role="identifier">push_wait_until</phrase><phrase
role="special">()</phrase></code> will not block until the number
of values in the channel becomes equal to <code><phrase role="identifier">capacity</phrase></code>.
The channel can hold only <code><phrase role="identifier">capacity</phrase>
<phrase role="special">-</phrase> <phrase role="number">1</phrase></code>
elements, otherwise it is considered to be full.
</para>
</listitem>
</varlistentry>
</variablelist>
<para>
<bridgehead renderas="sect4" id="buffered_channel_close_bridgehead">
<phrase id="buffered_channel_close"/>
<link linkend="buffered_channel_close">Member
function <code>close</code>()</link>
</bridgehead>
</para>
<programlisting><phrase role="keyword">void</phrase> <phrase role="identifier">close</phrase><phrase role="special">()</phrase> <phrase role="keyword">noexcept</phrase><phrase role="special">;</phrase>
</programlisting>
<variablelist>
<title></title>
<varlistentry>
<term>Effects:</term>
<listitem>
<para>
Deactivates the channel. No values can be put after calling <code><phrase
role="keyword">this</phrase><phrase role="special">-&gt;</phrase><phrase
role="identifier">close</phrase><phrase role="special">()</phrase></code>.
Fibers blocked in <code><phrase role="keyword">this</phrase><phrase
role="special">-&gt;</phrase><phrase role="identifier">pop</phrase><phrase
role="special">()</phrase></code>, <code><phrase role="keyword">this</phrase><phrase
role="special">-&gt;</phrase><phrase role="identifier">pop_wait_for</phrase><phrase
role="special">()</phrase></code> or <code><phrase role="keyword">this</phrase><phrase
role="special">-&gt;</phrase><phrase role="identifier">pop_wait_until</phrase><phrase
role="special">()</phrase></code> will return <code><phrase role="identifier">closed</phrase></code>.
Fibers blocked in <code><phrase role="keyword">this</phrase><phrase
role="special">-&gt;</phrase><phrase role="identifier">value_pop</phrase><phrase
role="special">()</phrase></code> will receive an exception.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>Throws:</term>
<listitem>
<para>
Nothing.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>Note:</term>
<listitem>
<para>
<code><phrase role="identifier">close</phrase><phrase role="special">()</phrase></code>
is like closing a pipe. It informs waiting consumers that no more
values will arrive.
</para>
</listitem>
</varlistentry>
</variablelist>
<para>
<bridgehead renderas="sect4" id="buffered_channel_push_bridgehead">
<phrase id="buffered_channel_push"/>
<link linkend="buffered_channel_push">Member
function <code>push</code>()</link>
</bridgehead>
</para>
<programlisting><phrase role="identifier">channel_op_status</phrase> <phrase role="identifier">push</phrase><phrase role="special">(</phrase> <phrase role="identifier">value_type</phrase> <phrase role="keyword">const</phrase><phrase role="special">&amp;</phrase> <phrase role="identifier">va</phrase><phrase role="special">);</phrase>
<phrase role="identifier">channel_op_status</phrase> <phrase role="identifier">push</phrase><phrase role="special">(</phrase> <phrase role="identifier">value_type</phrase> <phrase role="special">&amp;&amp;</phrase> <phrase role="identifier">va</phrase><phrase role="special">);</phrase>
</programlisting>
<variablelist>
<title></title>
<varlistentry>
<term>Effects:</term>
<listitem>
<para>
If channel is closed, returns <code><phrase role="identifier">closed</phrase></code>.
Otherwise enqueues the value in the channel, wakes up a fiber blocked
on <code><phrase role="keyword">this</phrase><phrase role="special">-&gt;</phrase><phrase
role="identifier">pop</phrase><phrase role="special">()</phrase></code>,
<code><phrase role="keyword">this</phrase><phrase role="special">-&gt;</phrase><phrase
role="identifier">value_pop</phrase><phrase role="special">()</phrase></code>,
<code><phrase role="keyword">this</phrase><phrase role="special">-&gt;</phrase><phrase
role="identifier">pop_wait_for</phrase><phrase role="special">()</phrase></code>
or <code><phrase role="keyword">this</phrase><phrase role="special">-&gt;</phrase><phrase
role="identifier">pop_wait_until</phrase><phrase role="special">()</phrase></code>
and returns <code><phrase role="identifier">success</phrase></code>.
If the channel is full, the fiber is blocked.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>Throws:</term>
<listitem>
<para>
Exceptions thrown by copy- or move-operations.
</para>
</listitem>
</varlistentry>
</variablelist>
<para>
<bridgehead renderas="sect4" id="buffered_channel_try_push_bridgehead">
<phrase id="buffered_channel_try_push"/>
<link linkend="buffered_channel_try_push">Member
function <code>try_push</code>()</link>
</bridgehead>
</para>
<programlisting><phrase role="identifier">channel_op_status</phrase> <phrase role="identifier">try_push</phrase><phrase role="special">(</phrase> <phrase role="identifier">value_type</phrase> <phrase role="keyword">const</phrase><phrase role="special">&amp;</phrase> <phrase role="identifier">va</phrase><phrase role="special">);</phrase>
<phrase role="identifier">channel_op_status</phrase> <phrase role="identifier">try_push</phrase><phrase role="special">(</phrase> <phrase role="identifier">value_type</phrase> <phrase role="special">&amp;&amp;</phrase> <phrase role="identifier">va</phrase><phrase role="special">);</phrase>
</programlisting>
<variablelist>
<title></title>
<varlistentry>
<term>Effects:</term>
<listitem>
<para>
If channel is closed, returns <code><phrase role="identifier">closed</phrase></code>.
Otherwise enqueues the value in the channel, wakes up a fiber blocked
on <code><phrase role="keyword">this</phrase><phrase role="special">-&gt;</phrase><phrase
role="identifier">pop</phrase><phrase role="special">()</phrase></code>,
<code><phrase role="keyword">this</phrase><phrase role="special">-&gt;</phrase><phrase
role="identifier">value_pop</phrase><phrase role="special">()</phrase></code>,
<code><phrase role="keyword">this</phrase><phrase role="special">-&gt;</phrase><phrase
role="identifier">pop_wait_for</phrase><phrase role="special">()</phrase></code>
or <code><phrase role="keyword">this</phrase><phrase role="special">-&gt;</phrase><phrase
role="identifier">pop_wait_until</phrase><phrase role="special">()</phrase></code>
and returns <code><phrase role="identifier">success</phrase></code>.
If the channel is full, it doesn't block and returns <code><phrase
role="identifier">full</phrase></code>.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>Throws:</term>
<listitem>
<para>
Exceptions thrown by copy- or move-operations.
</para>
</listitem>
</varlistentry>
</variablelist>
<para>
<bridgehead renderas="sect4" id="buffered_channel_pop_bridgehead">
<phrase id="buffered_channel_pop"/>
<link linkend="buffered_channel_pop">Member
function <code>pop</code>()</link>
</bridgehead>
</para>
<programlisting><phrase role="identifier">channel_op_status</phrase> <phrase role="identifier">pop</phrase><phrase role="special">(</phrase> <phrase role="identifier">value_type</phrase> <phrase role="special">&amp;</phrase> <phrase role="identifier">va</phrase><phrase role="special">);</phrase>
</programlisting>
<variablelist>
<title></title>
<varlistentry>
<term>Effects:</term>
<listitem>
<para>
Dequeues a value from the channel. If the channel is empty, the fiber
gets suspended until at least one new item is <code><phrase role="identifier">push</phrase><phrase
role="special">()</phrase></code>ed (return value <code><phrase role="identifier">success</phrase></code>
and <code><phrase role="identifier">va</phrase></code> contains dequeued
value) or the channel gets <code><phrase role="identifier">close</phrase><phrase
role="special">()</phrase></code>d (return value <code><phrase role="identifier">closed</phrase></code>).
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>Throws:</term>
<listitem>
<para>
Exceptions thrown by copy- or move-operations.
</para>
</listitem>
</varlistentry>
</variablelist>
<para>
<bridgehead renderas="sect4" id="buffered_channel_value_pop_bridgehead">
<phrase id="buffered_channel_value_pop"/>
<link linkend="buffered_channel_value_pop">Member
function <code>value_pop</code>()</link>
</bridgehead>
</para>
<programlisting><phrase role="identifier">value_type</phrase> <phrase role="identifier">value_pop</phrase><phrase role="special">();</phrase>
</programlisting>
<variablelist>
<title></title>
<varlistentry>
<term>Effects:</term>
<listitem>
<para>
Dequeues a value from the channel. If the channel is empty, the fiber
gets suspended until at least one new item is <code><phrase role="identifier">push</phrase><phrase
role="special">()</phrase></code>ed or the channel gets <code><phrase
role="identifier">close</phrase><phrase role="special">()</phrase></code>d
(which throws an exception).
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>Throws:</term>
<listitem>
<para>
<code><phrase role="identifier">fiber_error</phrase></code> if <code><phrase
role="special">*</phrase><phrase role="keyword">this</phrase></code>
is closed or by copy- or move-operations.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>Error conditions:</term>
<listitem>
<para>
<code><phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase
role="identifier">errc</phrase><phrase role="special">::</phrase><phrase
role="identifier">operation_not_permitted</phrase></code>
</para>
</listitem>
</varlistentry>
</variablelist>
<para>
<bridgehead renderas="sect4" id="buffered_channel_try_pop_bridgehead">
<phrase id="buffered_channel_try_pop"/>
<link linkend="buffered_channel_try_pop">Member
function <code>try_pop</code>()</link>
</bridgehead>
</para>
<programlisting><phrase role="identifier">channel_op_status</phrase> <phrase role="identifier">try_pop</phrase><phrase role="special">(</phrase> <phrase role="identifier">value_type</phrase> <phrase role="special">&amp;</phrase> <phrase role="identifier">va</phrase><phrase role="special">);</phrase>
</programlisting>
<variablelist>
<title></title>
<varlistentry>
<term>Effects:</term>
<listitem>
<para>
If channel is empty, returns <code><phrase role="identifier">empty</phrase></code>.
If channel is closed, returns <code><phrase role="identifier">closed</phrase></code>.
Otherwise it returns <code><phrase role="identifier">success</phrase></code>
and <code><phrase role="identifier">va</phrase></code> contains the
dequeued value.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>Throws:</term>
<listitem>
<para>
Exceptions thrown by copy- or move-operations.
</para>
</listitem>
</varlistentry>
</variablelist>
<para>
<bridgehead renderas="sect4" id="buffered_channel_pop_wait_for_bridgehead">
<phrase id="buffered_channel_pop_wait_for"/>
<link linkend="buffered_channel_pop_wait_for">Member
function <code>pop_wait_for</code>()</link>
</bridgehead>
</para>
<programlisting><phrase role="keyword">template</phrase><phrase role="special">&lt;</phrase> <phrase role="keyword">typename</phrase> <phrase role="identifier">Rep</phrase><phrase role="special">,</phrase> <phrase role="keyword">typename</phrase> <phrase role="identifier">Period</phrase> <phrase role="special">&gt;</phrase>
<phrase role="identifier">channel_op_status</phrase> <phrase role="identifier">pop_wait_for</phrase><phrase role="special">(</phrase>
<phrase role="identifier">value_type</phrase> <phrase role="special">&amp;</phrase> <phrase role="identifier">va</phrase><phrase role="special">,</phrase>
<phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">chrono</phrase><phrase role="special">::</phrase><phrase role="identifier">duration</phrase><phrase role="special">&lt;</phrase> <phrase role="identifier">Rep</phrase><phrase role="special">,</phrase> <phrase role="identifier">Period</phrase> <phrase role="special">&gt;</phrase> <phrase role="keyword">const</phrase><phrase role="special">&amp;</phrase> <phrase role="identifier">timeout_duration</phrase><phrase role="special">)</phrase>
</programlisting>
<variablelist>
<title></title>
<varlistentry>
<term>Effects:</term>
<listitem>
<para>
Accepts <code><phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase
role="identifier">chrono</phrase><phrase role="special">::</phrase><phrase
role="identifier">duration</phrase></code> and internally computes
a timeout time as (system time + <code><phrase role="identifier">timeout_duration</phrase></code>).
If channel is not empty, immediately dequeues a value from the channel.
Otherwise the fiber gets suspended until at least one new item is
<code><phrase role="identifier">push</phrase><phrase role="special">()</phrase></code>ed
(return value <code><phrase role="identifier">success</phrase></code>
and <code><phrase role="identifier">va</phrase></code> contains dequeued
value), or the channel gets <code><phrase role="identifier">close</phrase><phrase
role="special">()</phrase></code>d (return value <code><phrase role="identifier">closed</phrase></code>),
or the system time reaches the computed timeout time (return value
<code><phrase role="identifier">timeout</phrase></code>).
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>Throws:</term>
<listitem>
<para>
timeout-related exceptions or by copy- or move-operations.
</para>
</listitem>
</varlistentry>
</variablelist>
<para>
<bridgehead renderas="sect4" id="buffered_channel_pop_wait_until_bridgehead">
<phrase id="buffered_channel_pop_wait_until"/>
<link linkend="buffered_channel_pop_wait_until">Member
function <code>pop_wait_until</code>()</link>
</bridgehead>
</para>
<programlisting><phrase role="keyword">template</phrase><phrase role="special">&lt;</phrase> <phrase role="keyword">typename</phrase> <phrase role="identifier">Clock</phrase><phrase role="special">,</phrase> <phrase role="keyword">typename</phrase> <phrase role="identifier">Duration</phrase> <phrase role="special">&gt;</phrase>
<phrase role="identifier">channel_op_status</phrase> <phrase role="identifier">pop_wait_until</phrase><phrase role="special">(</phrase>
<phrase role="identifier">value_type</phrase> <phrase role="special">&amp;</phrase> <phrase role="identifier">va</phrase><phrase role="special">,</phrase>
<phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">chrono</phrase><phrase role="special">::</phrase><phrase role="identifier">time_point</phrase><phrase role="special">&lt;</phrase> <phrase role="identifier">Clock</phrase><phrase role="special">,</phrase> <phrase role="identifier">Duration</phrase> <phrase role="special">&gt;</phrase> <phrase role="keyword">const</phrase><phrase role="special">&amp;</phrase> <phrase role="identifier">timeout_time</phrase><phrase role="special">)</phrase>
</programlisting>
<variablelist>
<title></title>
<varlistentry>
<term>Effects:</term>
<listitem>
<para>
Accepts a <code><phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase
role="identifier">chrono</phrase><phrase role="special">::</phrase><phrase
role="identifier">time_point</phrase><phrase role="special">&lt;</phrase>
<phrase role="identifier">Clock</phrase><phrase role="special">,</phrase>
<phrase role="identifier">Duration</phrase> <phrase role="special">&gt;</phrase></code>.
If channel is not empty, immediately dequeues a value from the channel.
Otherwise the fiber gets suspended until at least one new item is
<code><phrase role="identifier">push</phrase><phrase role="special">()</phrase></code>ed
(return value <code><phrase role="identifier">success</phrase></code>
and <code><phrase role="identifier">va</phrase></code> contains dequeued
value), or the channel gets <code><phrase role="identifier">close</phrase><phrase
role="special">()</phrase></code>d (return value <code><phrase role="identifier">closed</phrase></code>),
or the system time reaches the passed <code><phrase role="identifier">time_point</phrase></code>
(return value <code><phrase role="identifier">timeout</phrase></code>).
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>Throws:</term>
<listitem>
<para>
timeout-related exceptions or by copy- or move-operations.
</para>
</listitem>
</varlistentry>
</variablelist>
<bridgehead renderas="sect5" id="fiber.synchronization.channels.buffered_channel.h1">
<phrase id="fiber.synchronization.channels.buffered_channel.non_member_function__code__phrase_role__identifier__begin__phrase__phrase_role__special_____phrase___phrase_role__identifier__buffered_channel__phrase__phrase_role__special___lt___phrase___phrase_role__identifier__t__phrase___phrase_role__special___gt___phrase___phrase_role__special___amp____phrase___code_"/><link
linkend="fiber.synchronization.channels.buffered_channel.non_member_function__code__phrase_role__identifier__begin__phrase__phrase_role__special_____phrase___phrase_role__identifier__buffered_channel__phrase__phrase_role__special___lt___phrase___phrase_role__identifier__t__phrase___phrase_role__special___gt___phrase___phrase_role__special___amp____phrase___code_">Non-member
function <code><phrase role="identifier">begin</phrase><phrase role="special">(</phrase>
<phrase role="identifier">buffered_channel</phrase><phrase role="special">&lt;</phrase>
<phrase role="identifier">T</phrase> <phrase role="special">&gt;</phrase>
<phrase role="special">&amp;)</phrase></code></link>
</bridgehead>
<programlisting><phrase role="keyword">template</phrase><phrase role="special">&lt;</phrase> <phrase role="keyword">typename</phrase> <phrase role="identifier">T</phrase> <phrase role="special">&gt;</phrase>
<phrase role="identifier">buffered_channel</phrase><phrase role="special">&lt;</phrase> <phrase role="identifier">T</phrase> <phrase role="special">&gt;::</phrase><phrase role="identifier">iterator</phrase> <phrase role="identifier">begin</phrase><phrase role="special">(</phrase> <phrase role="identifier">buffered_channel</phrase><phrase role="special">&lt;</phrase> <phrase role="identifier">T</phrase> <phrase role="special">&gt;</phrase> <phrase role="special">&amp;);</phrase>
</programlisting>
<variablelist>
<title></title>
<varlistentry>
<term>Returns:</term>
<listitem>
<para>
Returns a range-iterator (input-iterator).
</para>
</listitem>
</varlistentry>
</variablelist>
<bridgehead renderas="sect5" id="fiber.synchronization.channels.buffered_channel.h2">
<phrase id="fiber.synchronization.channels.buffered_channel.non_member_function__code__phrase_role__identifier__end__phrase__phrase_role__special_____phrase___phrase_role__identifier__buffered_channel__phrase__phrase_role__special___lt___phrase___phrase_role__identifier__t__phrase___phrase_role__special___gt___phrase___phrase_role__special___amp____phrase___code_"/><link
linkend="fiber.synchronization.channels.buffered_channel.non_member_function__code__phrase_role__identifier__end__phrase__phrase_role__special_____phrase___phrase_role__identifier__buffered_channel__phrase__phrase_role__special___lt___phrase___phrase_role__identifier__t__phrase___phrase_role__special___gt___phrase___phrase_role__special___amp____phrase___code_">Non-member
function <code><phrase role="identifier">end</phrase><phrase role="special">(</phrase>
<phrase role="identifier">buffered_channel</phrase><phrase role="special">&lt;</phrase>
<phrase role="identifier">T</phrase> <phrase role="special">&gt;</phrase>
<phrase role="special">&amp;)</phrase></code></link>
</bridgehead>
<programlisting><phrase role="keyword">template</phrase><phrase role="special">&lt;</phrase> <phrase role="keyword">typename</phrase> <phrase role="identifier">T</phrase> <phrase role="special">&gt;</phrase>
<phrase role="identifier">buffered_channel</phrase><phrase role="special">&lt;</phrase> <phrase role="identifier">R</phrase> <phrase role="special">&gt;::</phrase><phrase role="identifier">iterator</phrase> <phrase role="identifier">end</phrase><phrase role="special">(</phrase> <phrase role="identifier">buffered_channel</phrase><phrase role="special">&lt;</phrase> <phrase role="identifier">T</phrase> <phrase role="special">&gt;</phrase> <phrase role="special">&amp;);</phrase>
</programlisting>
<variablelist>
<title></title>
<varlistentry>
<term>Returns:</term>
<listitem>
<para>
Returns an end range-iterator (input-iterator).
</para>
</listitem>
</varlistentry>
</variablelist>
</section>
<section id="fiber.synchronization.channels.unbuffered_channel">
<title><link linkend="fiber.synchronization.channels.unbuffered_channel">Unbuffered
Channel</link></title>
<para>
<emphasis role="bold">Boost.Fiber</emphasis> provides template <code><phrase
role="identifier">unbuffered_channel</phrase></code> suitable to synchonize
fibers (running on same or different threads) via synchronous message passing.
A fiber waiting to consume an value will block until the value is produced.
If a fiber attempts to send a value through an unbuffered channel and no
fiber is waiting to receive the value, the channel will block the sending
fiber.
</para>
<para>
The unbuffered channel acts as an <code><phrase role="identifier">rendezvous</phrase>
<phrase role="identifier">point</phrase></code>.
</para>
<programlisting><phrase role="keyword">typedef</phrase> <phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">fibers</phrase><phrase role="special">::</phrase><phrase role="identifier">unbuffered_channel</phrase><phrase role="special">&lt;</phrase> <phrase role="keyword">int</phrase> <phrase role="special">&gt;</phrase> <phrase role="identifier">channel_t</phrase><phrase role="special">;</phrase>
<phrase role="keyword">void</phrase> <phrase role="identifier">send</phrase><phrase role="special">(</phrase> <phrase role="identifier">channel_t</phrase> <phrase role="special">&amp;</phrase> <phrase role="identifier">chan</phrase><phrase role="special">)</phrase> <phrase role="special">{</phrase>
<phrase role="keyword">for</phrase> <phrase role="special">(</phrase> <phrase role="keyword">int</phrase> <phrase role="identifier">i</phrase> <phrase role="special">=</phrase> <phrase role="number">0</phrase><phrase role="special">;</phrase> <phrase role="identifier">i</phrase> <phrase role="special">&lt;</phrase> <phrase role="number">5</phrase><phrase role="special">;</phrase> <phrase role="special">++</phrase><phrase role="identifier">i</phrase><phrase role="special">)</phrase> <phrase role="special">{</phrase>
<phrase role="identifier">chan</phrase><phrase role="special">.</phrase><phrase role="identifier">push</phrase><phrase role="special">(</phrase> <phrase role="identifier">i</phrase><phrase role="special">);</phrase>
<phrase role="special">}</phrase>
<phrase role="identifier">chan</phrase><phrase role="special">.</phrase><phrase role="identifier">close</phrase><phrase role="special">();</phrase>
<phrase role="special">}</phrase>
<phrase role="keyword">void</phrase> <phrase role="identifier">recv</phrase><phrase role="special">(</phrase> <phrase role="identifier">channel_t</phrase> <phrase role="special">&amp;</phrase> <phrase role="identifier">chan</phrase><phrase role="special">)</phrase> <phrase role="special">{</phrase>
<phrase role="keyword">int</phrase> <phrase role="identifier">i</phrase><phrase role="special">;</phrase>
<phrase role="keyword">while</phrase> <phrase role="special">(</phrase> <phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">fibers</phrase><phrase role="special">::</phrase><phrase role="identifier">channel_op_status</phrase><phrase role="special">::</phrase><phrase role="identifier">success</phrase> <phrase role="special">==</phrase> <phrase role="identifier">chan</phrase><phrase role="special">.</phrase><phrase role="identifier">pop</phrase><phrase role="special">(</phrase><phrase role="identifier">i</phrase><phrase role="special">)</phrase> <phrase role="special">)</phrase> <phrase role="special">{</phrase>
<phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">cout</phrase> <phrase role="special">&lt;&lt;</phrase> <phrase role="string">&quot;received &quot;</phrase> <phrase role="special">&lt;&lt;</phrase> <phrase role="identifier">i</phrase> <phrase role="special">&lt;&lt;</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">endl</phrase><phrase role="special">;</phrase>
<phrase role="special">}</phrase>
<phrase role="special">}</phrase>
<phrase role="identifier">channel_t</phrase> <phrase role="identifier">chan</phrase><phrase role="special">{</phrase> <phrase role="number">1</phrase> <phrase role="special">};</phrase>
<phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">fibers</phrase><phrase role="special">::</phrase><phrase role="identifier">fiber</phrase> <phrase role="identifier">f1</phrase><phrase role="special">(</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">bind</phrase><phrase role="special">(</phrase> <phrase role="identifier">send</phrase><phrase role="special">,</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">ref</phrase><phrase role="special">(</phrase> <phrase role="identifier">chan</phrase><phrase role="special">)</phrase> <phrase role="special">)</phrase> <phrase role="special">);</phrase>
<phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">fibers</phrase><phrase role="special">::</phrase><phrase role="identifier">fiber</phrase> <phrase role="identifier">f2</phrase><phrase role="special">(</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">bind</phrase><phrase role="special">(</phrase> <phrase role="identifier">recv</phrase><phrase role="special">,</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">ref</phrase><phrase role="special">(</phrase> <phrase role="identifier">chan</phrase><phrase role="special">)</phrase> <phrase role="special">)</phrase> <phrase role="special">);</phrase>
<phrase role="identifier">f1</phrase><phrase role="special">.</phrase><phrase role="identifier">join</phrase><phrase role="special">();</phrase>
<phrase role="identifier">f2</phrase><phrase role="special">.</phrase><phrase role="identifier">join</phrase><phrase role="special">();</phrase>
</programlisting>
<para>
Range-for syntax is supported:
</para>
<programlisting><phrase role="keyword">typedef</phrase> <phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">fibers</phrase><phrase role="special">::</phrase><phrase role="identifier">unbuffered_channel</phrase><phrase role="special">&lt;</phrase> <phrase role="keyword">int</phrase> <phrase role="special">&gt;</phrase> <phrase role="identifier">channel_t</phrase><phrase role="special">;</phrase>
<phrase role="keyword">void</phrase> <phrase role="identifier">foo</phrase><phrase role="special">(</phrase> <phrase role="identifier">channel_t</phrase> <phrase role="special">&amp;</phrase> <phrase role="identifier">chan</phrase><phrase role="special">)</phrase> <phrase role="special">{</phrase>
<phrase role="identifier">chan</phrase><phrase role="special">.</phrase><phrase role="identifier">push</phrase><phrase role="special">(</phrase> <phrase role="number">1</phrase><phrase role="special">);</phrase>
<phrase role="identifier">chan</phrase><phrase role="special">.</phrase><phrase role="identifier">push</phrase><phrase role="special">(</phrase> <phrase role="number">1</phrase><phrase role="special">);</phrase>
<phrase role="identifier">chan</phrase><phrase role="special">.</phrase><phrase role="identifier">push</phrase><phrase role="special">(</phrase> <phrase role="number">2</phrase><phrase role="special">);</phrase>
<phrase role="identifier">chan</phrase><phrase role="special">.</phrase><phrase role="identifier">push</phrase><phrase role="special">(</phrase> <phrase role="number">3</phrase><phrase role="special">);</phrase>
<phrase role="identifier">chan</phrase><phrase role="special">.</phrase><phrase role="identifier">push</phrase><phrase role="special">(</phrase> <phrase role="number">5</phrase><phrase role="special">);</phrase>
<phrase role="identifier">chan</phrase><phrase role="special">.</phrase><phrase role="identifier">push</phrase><phrase role="special">(</phrase> <phrase role="number">8</phrase><phrase role="special">);</phrase>
<phrase role="identifier">chan</phrase><phrase role="special">.</phrase><phrase role="identifier">push</phrase><phrase role="special">(</phrase> <phrase role="number">12</phrase><phrase role="special">);</phrase>
<phrase role="identifier">chan</phrase><phrase role="special">.</phrase><phrase role="identifier">close</phrase><phrase role="special">();</phrase>
<phrase role="special">}</phrase>
<phrase role="keyword">void</phrase> <phrase role="identifier">bar</phrase><phrase role="special">(</phrase> <phrase role="identifier">channel_t</phrase> <phrase role="special">&amp;</phrase> <phrase role="identifier">chan</phrase><phrase role="special">)</phrase> <phrase role="special">{</phrase>
<phrase role="keyword">for</phrase> <phrase role="special">(</phrase> <phrase role="keyword">unsigned</phrase> <phrase role="keyword">int</phrase> <phrase role="identifier">value</phrase> <phrase role="special">:</phrase> <phrase role="identifier">chan</phrase><phrase role="special">)</phrase> <phrase role="special">{</phrase>
<phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">cout</phrase> <phrase role="special">&lt;&lt;</phrase> <phrase role="identifier">value</phrase> <phrase role="special">&lt;&lt;</phrase> <phrase role="string">&quot; &quot;</phrase><phrase role="special">;</phrase>
<phrase role="special">}</phrase>
<phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">cout</phrase> <phrase role="special">&lt;&lt;</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">endl</phrase><phrase role="special">;</phrase>
<phrase role="special">}</phrase>
</programlisting>
<para>
<bridgehead renderas="sect4" id="class_unbuffered_channel_bridgehead">
<phrase id="class_unbuffered_channel"/>
<link linkend="class_unbuffered_channel">Template
<code>unbuffered_channel&lt;&gt;</code></link>
</bridgehead>
</para>
<programlisting><phrase role="preprocessor">#include</phrase> <phrase role="special">&lt;</phrase><phrase role="identifier">boost</phrase><phrase role="special">/</phrase><phrase role="identifier">fiber</phrase><phrase role="special">/</phrase><phrase role="identifier">unbuffered_channel</phrase><phrase role="special">.</phrase><phrase role="identifier">hpp</phrase><phrase role="special">&gt;</phrase>
<phrase role="keyword">namespace</phrase> <phrase role="identifier">boost</phrase> <phrase role="special">{</phrase>
<phrase role="keyword">namespace</phrase> <phrase role="identifier">fibers</phrase> <phrase role="special">{</phrase>
<phrase role="keyword">template</phrase><phrase role="special">&lt;</phrase> <phrase role="keyword">typename</phrase> <phrase role="identifier">T</phrase> <phrase role="special">&gt;</phrase>
<phrase role="keyword">class</phrase> <phrase role="identifier">unbuffered_channel</phrase> <phrase role="special">{</phrase>
<phrase role="keyword">public</phrase><phrase role="special">:</phrase>
<phrase role="keyword">typedef</phrase> <phrase role="identifier">T</phrase> <phrase role="identifier">value_type</phrase><phrase role="special">;</phrase>
<phrase role="keyword">class</phrase> <phrase role="identifier">iterator</phrase><phrase role="special">;</phrase>
<phrase role="identifier">unbuffered_channel</phrase><phrase role="special">();</phrase>
<phrase role="identifier">unbuffered_channel</phrase><phrase role="special">(</phrase> <phrase role="identifier">unbuffered_channel</phrase> <phrase role="keyword">const</phrase><phrase role="special">&amp;</phrase> <phrase role="identifier">other</phrase><phrase role="special">)</phrase> <phrase role="special">=</phrase> <phrase role="keyword">delete</phrase><phrase role="special">;</phrase>
<phrase role="identifier">unbuffered_channel</phrase> <phrase role="special">&amp;</phrase> <phrase role="keyword">operator</phrase><phrase role="special">=(</phrase> <phrase role="identifier">unbuffered_channel</phrase> <phrase role="keyword">const</phrase><phrase role="special">&amp;</phrase> <phrase role="identifier">other</phrase><phrase role="special">)</phrase> <phrase role="special">=</phrase> <phrase role="keyword">delete</phrase><phrase role="special">;</phrase>
<phrase role="keyword">void</phrase> <phrase role="identifier">close</phrase><phrase role="special">()</phrase> <phrase role="keyword">noexcept</phrase><phrase role="special">;</phrase>
<phrase role="identifier">channel_op_status</phrase> <phrase role="identifier">push</phrase><phrase role="special">(</phrase> <phrase role="identifier">value_type</phrase> <phrase role="keyword">const</phrase><phrase role="special">&amp;</phrase> <phrase role="identifier">va</phrase><phrase role="special">);</phrase>
<phrase role="identifier">channel_op_status</phrase> <phrase role="identifier">push</phrase><phrase role="special">(</phrase> <phrase role="identifier">value_type</phrase> <phrase role="special">&amp;&amp;</phrase> <phrase role="identifier">va</phrase><phrase role="special">);</phrase>
<phrase role="keyword">template</phrase><phrase role="special">&lt;</phrase> <phrase role="keyword">typename</phrase> <phrase role="identifier">Rep</phrase><phrase role="special">,</phrase> <phrase role="keyword">typename</phrase> <phrase role="identifier">Period</phrase> <phrase role="special">&gt;</phrase>
<phrase role="identifier">channel_op_status</phrase> <phrase role="identifier">push_wait_for</phrase><phrase role="special">(</phrase>
<phrase role="identifier">value_type</phrase> <phrase role="keyword">const</phrase><phrase role="special">&amp;</phrase> <phrase role="identifier">va</phrase><phrase role="special">,</phrase>
<phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">chrono</phrase><phrase role="special">::</phrase><phrase role="identifier">duration</phrase><phrase role="special">&lt;</phrase> <phrase role="identifier">Rep</phrase><phrase role="special">,</phrase> <phrase role="identifier">Period</phrase> <phrase role="special">&gt;</phrase> <phrase role="keyword">const</phrase><phrase role="special">&amp;</phrase> <phrase role="identifier">timeout_duration</phrase><phrase role="special">);</phrase>
<phrase role="identifier">channel_op_status</phrase> <phrase role="identifier">push_wait_for</phrase><phrase role="special">(</phrase> <phrase role="identifier">value_type</phrase> <phrase role="special">&amp;&amp;</phrase> <phrase role="identifier">va</phrase><phrase role="special">,</phrase>
<phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">chrono</phrase><phrase role="special">::</phrase><phrase role="identifier">duration</phrase><phrase role="special">&lt;</phrase> <phrase role="identifier">Rep</phrase><phrase role="special">,</phrase> <phrase role="identifier">Period</phrase> <phrase role="special">&gt;</phrase> <phrase role="keyword">const</phrase><phrase role="special">&amp;</phrase> <phrase role="identifier">timeout_duration</phrase><phrase role="special">);</phrase>
<phrase role="keyword">template</phrase><phrase role="special">&lt;</phrase> <phrase role="keyword">typename</phrase> <phrase role="identifier">Clock</phrase><phrase role="special">,</phrase> <phrase role="keyword">typename</phrase> <phrase role="identifier">Duration</phrase> <phrase role="special">&gt;</phrase>
<phrase role="identifier">channel_op_status</phrase> <phrase role="identifier">push_wait_until</phrase><phrase role="special">(</phrase>
<phrase role="identifier">value_type</phrase> <phrase role="keyword">const</phrase><phrase role="special">&amp;</phrase> <phrase role="identifier">va</phrase><phrase role="special">,</phrase>
<phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">chrono</phrase><phrase role="special">::</phrase><phrase role="identifier">time_point</phrase><phrase role="special">&lt;</phrase> <phrase role="identifier">Clock</phrase><phrase role="special">,</phrase> <phrase role="identifier">Duration</phrase> <phrase role="special">&gt;</phrase> <phrase role="keyword">const</phrase><phrase role="special">&amp;</phrase> <phrase role="identifier">timeout_time</phrase><phrase role="special">);</phrase>
<phrase role="keyword">template</phrase><phrase role="special">&lt;</phrase> <phrase role="keyword">typename</phrase> <phrase role="identifier">Clock</phrase><phrase role="special">,</phrase> <phrase role="keyword">typename</phrase> <phrase role="identifier">Duration</phrase> <phrase role="special">&gt;</phrase>
<phrase role="identifier">channel_op_status</phrase> <phrase role="identifier">push_wait_until</phrase><phrase role="special">(</phrase>
<phrase role="identifier">value_type</phrase> <phrase role="special">&amp;&amp;</phrase> <phrase role="identifier">va</phrase><phrase role="special">,</phrase>
<phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">chrono</phrase><phrase role="special">::</phrase><phrase role="identifier">time_point</phrase><phrase role="special">&lt;</phrase> <phrase role="identifier">Clock</phrase><phrase role="special">,</phrase> <phrase role="identifier">Duration</phrase> <phrase role="special">&gt;</phrase> <phrase role="keyword">const</phrase><phrase role="special">&amp;</phrase> <phrase role="identifier">timeout_time</phrase><phrase role="special">);</phrase>
<phrase role="identifier">channel_op_status</phrase> <phrase role="identifier">pop</phrase><phrase role="special">(</phrase> <phrase role="identifier">value_type</phrase> <phrase role="special">&amp;</phrase> <phrase role="identifier">va</phrase><phrase role="special">);</phrase>
<phrase role="identifier">value_type</phrase> <phrase role="identifier">value_pop</phrase><phrase role="special">();</phrase>
<phrase role="keyword">template</phrase><phrase role="special">&lt;</phrase> <phrase role="keyword">typename</phrase> <phrase role="identifier">Rep</phrase><phrase role="special">,</phrase> <phrase role="keyword">typename</phrase> <phrase role="identifier">Period</phrase> <phrase role="special">&gt;</phrase>
<phrase role="identifier">channel_op_status</phrase> <phrase role="identifier">pop_wait_for</phrase><phrase role="special">(</phrase>
<phrase role="identifier">value_type</phrase> <phrase role="special">&amp;</phrase> <phrase role="identifier">va</phrase><phrase role="special">,</phrase>
<phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">chrono</phrase><phrase role="special">::</phrase><phrase role="identifier">duration</phrase><phrase role="special">&lt;</phrase> <phrase role="identifier">Rep</phrase><phrase role="special">,</phrase> <phrase role="identifier">Period</phrase> <phrase role="special">&gt;</phrase> <phrase role="keyword">const</phrase><phrase role="special">&amp;</phrase> <phrase role="identifier">timeout_duration</phrase><phrase role="special">);</phrase>
<phrase role="keyword">template</phrase><phrase role="special">&lt;</phrase> <phrase role="keyword">typename</phrase> <phrase role="identifier">Clock</phrase><phrase role="special">,</phrase> <phrase role="keyword">typename</phrase> <phrase role="identifier">Duration</phrase> <phrase role="special">&gt;</phrase>
<phrase role="identifier">channel_op_status</phrase> <phrase role="identifier">pop_wait_until</phrase><phrase role="special">(</phrase>
<phrase role="identifier">value_type</phrase> <phrase role="special">&amp;</phrase> <phrase role="identifier">va</phrase><phrase role="special">,</phrase>
<phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">chrono</phrase><phrase role="special">::</phrase><phrase role="identifier">time_point</phrase><phrase role="special">&lt;</phrase> <phrase role="identifier">Clock</phrase><phrase role="special">,</phrase> <phrase role="identifier">Duration</phrase> <phrase role="special">&gt;</phrase> <phrase role="keyword">const</phrase><phrase role="special">&amp;</phrase> <phrase role="identifier">timeout_time</phrase><phrase role="special">);</phrase>
<phrase role="special">};</phrase>
<phrase role="keyword">template</phrase><phrase role="special">&lt;</phrase> <phrase role="keyword">typename</phrase> <phrase role="identifier">T</phrase> <phrase role="special">&gt;</phrase>
<phrase role="identifier">unbuffered_channel</phrase><phrase role="special">&lt;</phrase> <phrase role="identifier">T</phrase> <phrase role="special">&gt;::</phrase><phrase role="identifier">iterator</phrase> <phrase role="identifier">begin</phrase><phrase role="special">(</phrase> <phrase role="identifier">unbuffered_channel</phrase><phrase role="special">&lt;</phrase> <phrase role="identifier">T</phrase> <phrase role="special">&gt;</phrase> <phrase role="special">&amp;</phrase> <phrase role="identifier">chan</phrase><phrase role="special">);</phrase>
<phrase role="keyword">template</phrase><phrase role="special">&lt;</phrase> <phrase role="keyword">typename</phrase> <phrase role="identifier">T</phrase> <phrase role="special">&gt;</phrase>
<phrase role="identifier">unbuffered_channel</phrase><phrase role="special">&lt;</phrase> <phrase role="identifier">T</phrase> <phrase role="special">&gt;::</phrase><phrase role="identifier">iterator</phrase> <phrase role="identifier">end</phrase><phrase role="special">(</phrase> <phrase role="identifier">unbuffered_channel</phrase><phrase role="special">&lt;</phrase> <phrase role="identifier">T</phrase> <phrase role="special">&gt;</phrase> <phrase role="special">&amp;</phrase> <phrase role="identifier">chan</phrase><phrase role="special">);</phrase>
<phrase role="special">}}</phrase>
</programlisting>
<bridgehead renderas="sect5" id="fiber.synchronization.channels.unbuffered_channel.h0">
<phrase id="fiber.synchronization.channels.unbuffered_channel.constructor"/><link
linkend="fiber.synchronization.channels.unbuffered_channel.constructor">Constructor</link>
</bridgehead>
<programlisting><phrase role="identifier">unbuffered_channel</phrase><phrase role="special">();</phrase>
</programlisting>
<variablelist>
<title></title>
<varlistentry>
<term>Effects:</term>
<listitem>
<para>
The constructor constructs an object of class <code><phrase role="identifier">unbuffered_channel</phrase></code>.
</para>
</listitem>
</varlistentry>
</variablelist>
<para>
<bridgehead renderas="sect4" id="unbuffered_channel_close_bridgehead">
<phrase id="unbuffered_channel_close"/>
<link linkend="unbuffered_channel_close">Member
function <code>close</code>()</link>
</bridgehead>
</para>
<programlisting><phrase role="keyword">void</phrase> <phrase role="identifier">close</phrase><phrase role="special">()</phrase> <phrase role="keyword">noexcept</phrase><phrase role="special">;</phrase>
</programlisting>
<variablelist>
<title></title>
<varlistentry>
<term>Effects:</term>
<listitem>
<para>
Deactivates the channel. No values can be put after calling <code><phrase
role="keyword">this</phrase><phrase role="special">-&gt;</phrase><phrase
role="identifier">close</phrase><phrase role="special">()</phrase></code>.
Fibers blocked in <code><phrase role="keyword">this</phrase><phrase
role="special">-&gt;</phrase><phrase role="identifier">pop</phrase><phrase
role="special">()</phrase></code>, <code><phrase role="keyword">this</phrase><phrase
role="special">-&gt;</phrase><phrase role="identifier">pop_wait_for</phrase><phrase
role="special">()</phrase></code> or <code><phrase role="keyword">this</phrase><phrase
role="special">-&gt;</phrase><phrase role="identifier">pop_wait_until</phrase><phrase
role="special">()</phrase></code> will return <code><phrase role="identifier">closed</phrase></code>.
Fibers blocked in <code><phrase role="keyword">this</phrase><phrase
role="special">-&gt;</phrase><phrase role="identifier">value_pop</phrase><phrase
role="special">()</phrase></code> will receive an exception.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>Throws:</term>
<listitem>
<para>
Nothing.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>Note:</term>
<listitem>
<para>
<code><phrase role="identifier">close</phrase><phrase role="special">()</phrase></code>
is like closing a pipe. It informs waiting consumers that no more
values will arrive.
</para>
</listitem>
</varlistentry>
</variablelist>
<para>
<bridgehead renderas="sect4" id="unbuffered_channel_push_bridgehead">
<phrase id="unbuffered_channel_push"/>
<link linkend="unbuffered_channel_push">Member
function <code>push</code>()</link>
</bridgehead>
</para>
<programlisting><phrase role="identifier">channel_op_status</phrase> <phrase role="identifier">push</phrase><phrase role="special">(</phrase> <phrase role="identifier">value_type</phrase> <phrase role="keyword">const</phrase><phrase role="special">&amp;</phrase> <phrase role="identifier">va</phrase><phrase role="special">);</phrase>
<phrase role="identifier">channel_op_status</phrase> <phrase role="identifier">push</phrase><phrase role="special">(</phrase> <phrase role="identifier">value_type</phrase> <phrase role="special">&amp;&amp;</phrase> <phrase role="identifier">va</phrase><phrase role="special">);</phrase>
</programlisting>
<variablelist>
<title></title>
<varlistentry>
<term>Effects:</term>
<listitem>
<para>
If channel is closed, returns <code><phrase role="identifier">closed</phrase></code>.
Otherwise enqueues the value in the channel, wakes up a fiber blocked
on <code><phrase role="keyword">this</phrase><phrase role="special">-&gt;</phrase><phrase
role="identifier">pop</phrase><phrase role="special">()</phrase></code>,
<code><phrase role="keyword">this</phrase><phrase role="special">-&gt;</phrase><phrase
role="identifier">value_pop</phrase><phrase role="special">()</phrase></code>,
<code><phrase role="keyword">this</phrase><phrase role="special">-&gt;</phrase><phrase
role="identifier">pop_wait_for</phrase><phrase role="special">()</phrase></code>
or <code><phrase role="keyword">this</phrase><phrase role="special">-&gt;</phrase><phrase
role="identifier">pop_wait_until</phrase><phrase role="special">()</phrase></code>
and returns <code><phrase role="identifier">success</phrase></code>.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>Throws:</term>
<listitem>
<para>
Exceptions thrown by copy- or move-operations.
</para>
</listitem>
</varlistentry>
</variablelist>
<para>
<bridgehead renderas="sect4" id="unbuffered_channel_pop_bridgehead">
<phrase id="unbuffered_channel_pop"/>
<link linkend="unbuffered_channel_pop">Member
function <code>pop</code>()</link>
</bridgehead>
</para>
<programlisting><phrase role="identifier">channel_op_status</phrase> <phrase role="identifier">pop</phrase><phrase role="special">(</phrase> <phrase role="identifier">value_type</phrase> <phrase role="special">&amp;</phrase> <phrase role="identifier">va</phrase><phrase role="special">);</phrase>
</programlisting>
<variablelist>
<title></title>
<varlistentry>
<term>Effects:</term>
<listitem>
<para>
Dequeues a value from the channel. If the channel is empty, the fiber
gets suspended until at least one new item is <code><phrase role="identifier">push</phrase><phrase
role="special">()</phrase></code>ed (return value <code><phrase role="identifier">success</phrase></code>
and <code><phrase role="identifier">va</phrase></code> contains dequeued
value) or the channel gets <code><phrase role="identifier">close</phrase><phrase
role="special">()</phrase></code>d (return value <code><phrase role="identifier">closed</phrase></code>).
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>Throws:</term>
<listitem>
<para>
Exceptions thrown by copy- or move-operations.
</para>
</listitem>
</varlistentry>
</variablelist>
<para>
<bridgehead renderas="sect4" id="unbuffered_channel_value_pop_bridgehead">
<phrase id="unbuffered_channel_value_pop"/>
<link linkend="unbuffered_channel_value_pop">Member
function <code>value_pop</code>()</link>
</bridgehead>
</para>
<programlisting><phrase role="identifier">value_type</phrase> <phrase role="identifier">value_pop</phrase><phrase role="special">();</phrase>
</programlisting>
<variablelist>
<title></title>
<varlistentry>
<term>Effects:</term>
<listitem>
<para>
Dequeues a value from the channel. If the channel is empty, the fiber
gets suspended until at least one new item is <code><phrase role="identifier">push</phrase><phrase
role="special">()</phrase></code>ed or the channel gets <code><phrase
role="identifier">close</phrase><phrase role="special">()</phrase></code>d
(which throws an exception).
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>Throws:</term>
<listitem>
<para>
<code><phrase role="identifier">fiber_error</phrase></code> if <code><phrase
role="special">*</phrase><phrase role="keyword">this</phrase></code>
is closed or by copy- or move-operations.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>Error conditions:</term>
<listitem>
<para>
<code><phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase
role="identifier">errc</phrase><phrase role="special">::</phrase><phrase
role="identifier">operation_not_permitted</phrase></code>
</para>
</listitem>
</varlistentry>
</variablelist>
<para>
<bridgehead renderas="sect4" id="unbuffered_channel_pop_wait_for_bridgehead">
<phrase id="unbuffered_channel_pop_wait_for"/>
<link linkend="unbuffered_channel_pop_wait_for">Member
function <code>pop_wait_for</code>()</link>
</bridgehead>
</para>
<programlisting><phrase role="keyword">template</phrase><phrase role="special">&lt;</phrase> <phrase role="keyword">typename</phrase> <phrase role="identifier">Rep</phrase><phrase role="special">,</phrase> <phrase role="keyword">typename</phrase> <phrase role="identifier">Period</phrase> <phrase role="special">&gt;</phrase>
<phrase role="identifier">channel_op_status</phrase> <phrase role="identifier">pop_wait_for</phrase><phrase role="special">(</phrase>
<phrase role="identifier">value_type</phrase> <phrase role="special">&amp;</phrase> <phrase role="identifier">va</phrase><phrase role="special">,</phrase>
<phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">chrono</phrase><phrase role="special">::</phrase><phrase role="identifier">duration</phrase><phrase role="special">&lt;</phrase> <phrase role="identifier">Rep</phrase><phrase role="special">,</phrase> <phrase role="identifier">Period</phrase> <phrase role="special">&gt;</phrase> <phrase role="keyword">const</phrase><phrase role="special">&amp;</phrase> <phrase role="identifier">timeout_duration</phrase><phrase role="special">)</phrase>
</programlisting>
<variablelist>
<title></title>
<varlistentry>
<term>Effects:</term>
<listitem>
<para>
Accepts <code><phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase
role="identifier">chrono</phrase><phrase role="special">::</phrase><phrase
role="identifier">duration</phrase></code> and internally computes
a timeout time as (system time + <code><phrase role="identifier">timeout_duration</phrase></code>).
If channel is not empty, immediately dequeues a value from the channel.
Otherwise the fiber gets suspended until at least one new item is
<code><phrase role="identifier">push</phrase><phrase role="special">()</phrase></code>ed
(return value <code><phrase role="identifier">success</phrase></code>
and <code><phrase role="identifier">va</phrase></code> contains dequeued
value), or the channel gets <code><phrase role="identifier">close</phrase><phrase
role="special">()</phrase></code>d (return value <code><phrase role="identifier">closed</phrase></code>),
or the system time reaches the computed timeout time (return value
<code><phrase role="identifier">timeout</phrase></code>).
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>Throws:</term>
<listitem>
<para>
timeout-related exceptions or by copy- or move-operations.
</para>
</listitem>
</varlistentry>
</variablelist>
<para>
<bridgehead renderas="sect4" id="unbuffered_channel_pop_wait_until_bridgehead">
<phrase id="unbuffered_channel_pop_wait_until"/>
<link linkend="unbuffered_channel_pop_wait_until">Member
function <code>pop_wait_until</code>()</link>
</bridgehead>
</para>
<programlisting><phrase role="keyword">template</phrase><phrase role="special">&lt;</phrase> <phrase role="keyword">typename</phrase> <phrase role="identifier">Clock</phrase><phrase role="special">,</phrase> <phrase role="keyword">typename</phrase> <phrase role="identifier">Duration</phrase> <phrase role="special">&gt;</phrase>
<phrase role="identifier">channel_op_status</phrase> <phrase role="identifier">pop_wait_until</phrase><phrase role="special">(</phrase>
<phrase role="identifier">value_type</phrase> <phrase role="special">&amp;</phrase> <phrase role="identifier">va</phrase><phrase role="special">,</phrase>
<phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">chrono</phrase><phrase role="special">::</phrase><phrase role="identifier">time_point</phrase><phrase role="special">&lt;</phrase> <phrase role="identifier">Clock</phrase><phrase role="special">,</phrase> <phrase role="identifier">Duration</phrase> <phrase role="special">&gt;</phrase> <phrase role="keyword">const</phrase><phrase role="special">&amp;</phrase> <phrase role="identifier">timeout_time</phrase><phrase role="special">)</phrase>
</programlisting>
<variablelist>
<title></title>
<varlistentry>
<term>Effects:</term>
<listitem>
<para>
Accepts a <code><phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase
role="identifier">chrono</phrase><phrase role="special">::</phrase><phrase
role="identifier">time_point</phrase><phrase role="special">&lt;</phrase>
<phrase role="identifier">Clock</phrase><phrase role="special">,</phrase>
<phrase role="identifier">Duration</phrase> <phrase role="special">&gt;</phrase></code>.
If channel is not empty, immediately dequeues a value from the channel.
Otherwise the fiber gets suspended until at least one new item is
<code><phrase role="identifier">push</phrase><phrase role="special">()</phrase></code>ed
(return value <code><phrase role="identifier">success</phrase></code>
and <code><phrase role="identifier">va</phrase></code> contains dequeued
value), or the channel gets <code><phrase role="identifier">close</phrase><phrase
role="special">()</phrase></code>d (return value <code><phrase role="identifier">closed</phrase></code>),
or the system time reaches the passed <code><phrase role="identifier">time_point</phrase></code>
(return value <code><phrase role="identifier">timeout</phrase></code>).
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>Throws:</term>
<listitem>
<para>
timeout-related exceptions or by copy- or move-operations.
</para>
</listitem>
</varlistentry>
</variablelist>
<bridgehead renderas="sect5" id="fiber.synchronization.channels.unbuffered_channel.h1">
<phrase id="fiber.synchronization.channels.unbuffered_channel.non_member_function__code__phrase_role__identifier__begin__phrase__phrase_role__special_____phrase___phrase_role__identifier__unbuffered_channel__phrase__phrase_role__special___lt___phrase___phrase_role__identifier__t__phrase___phrase_role__special___gt___phrase___phrase_role__special___amp____phrase___code_"/><link
linkend="fiber.synchronization.channels.unbuffered_channel.non_member_function__code__phrase_role__identifier__begin__phrase__phrase_role__special_____phrase___phrase_role__identifier__unbuffered_channel__phrase__phrase_role__special___lt___phrase___phrase_role__identifier__t__phrase___phrase_role__special___gt___phrase___phrase_role__special___amp____phrase___code_">Non-member
function <code><phrase role="identifier">begin</phrase><phrase role="special">(</phrase>
<phrase role="identifier">unbuffered_channel</phrase><phrase role="special">&lt;</phrase>
<phrase role="identifier">T</phrase> <phrase role="special">&gt;</phrase>
<phrase role="special">&amp;)</phrase></code></link>
</bridgehead>
<programlisting><phrase role="keyword">template</phrase><phrase role="special">&lt;</phrase> <phrase role="keyword">typename</phrase> <phrase role="identifier">T</phrase> <phrase role="special">&gt;</phrase>
<phrase role="identifier">unbuffered_channel</phrase><phrase role="special">&lt;</phrase> <phrase role="identifier">T</phrase> <phrase role="special">&gt;::</phrase><phrase role="identifier">iterator</phrase> <phrase role="identifier">begin</phrase><phrase role="special">(</phrase> <phrase role="identifier">unbuffered_channel</phrase><phrase role="special">&lt;</phrase> <phrase role="identifier">T</phrase> <phrase role="special">&gt;</phrase> <phrase role="special">&amp;);</phrase>
</programlisting>
<variablelist>
<title></title>
<varlistentry>
<term>Returns:</term>
<listitem>
<para>
Returns a range-iterator (input-iterator).
</para>
</listitem>
</varlistentry>
</variablelist>
<bridgehead renderas="sect5" id="fiber.synchronization.channels.unbuffered_channel.h2">
<phrase id="fiber.synchronization.channels.unbuffered_channel.non_member_function__code__phrase_role__identifier__end__phrase__phrase_role__special_____phrase___phrase_role__identifier__unbuffered_channel__phrase__phrase_role__special___lt___phrase___phrase_role__identifier__t__phrase___phrase_role__special___gt___phrase___phrase_role__special___amp____phrase___code_"/><link
linkend="fiber.synchronization.channels.unbuffered_channel.non_member_function__code__phrase_role__identifier__end__phrase__phrase_role__special_____phrase___phrase_role__identifier__unbuffered_channel__phrase__phrase_role__special___lt___phrase___phrase_role__identifier__t__phrase___phrase_role__special___gt___phrase___phrase_role__special___amp____phrase___code_">Non-member
function <code><phrase role="identifier">end</phrase><phrase role="special">(</phrase>
<phrase role="identifier">unbuffered_channel</phrase><phrase role="special">&lt;</phrase>
<phrase role="identifier">T</phrase> <phrase role="special">&gt;</phrase>
<phrase role="special">&amp;)</phrase></code></link>
</bridgehead>
<programlisting><phrase role="keyword">template</phrase><phrase role="special">&lt;</phrase> <phrase role="keyword">typename</phrase> <phrase role="identifier">T</phrase> <phrase role="special">&gt;</phrase>
<phrase role="identifier">unbuffered_channel</phrase><phrase role="special">&lt;</phrase> <phrase role="identifier">R</phrase> <phrase role="special">&gt;::</phrase><phrase role="identifier">iterator</phrase> <phrase role="identifier">end</phrase><phrase role="special">(</phrase> <phrase role="identifier">unbuffered_channel</phrase><phrase role="special">&lt;</phrase> <phrase role="identifier">T</phrase> <phrase role="special">&gt;</phrase> <phrase role="special">&amp;);</phrase>
</programlisting>
<variablelist>
<title></title>
<varlistentry>
<term>Returns:</term>
<listitem>
<para>
Returns an end range-iterator (input-iterator).
</para>
</listitem>
</varlistentry>
</variablelist>
</section>
</section>
<section id="fiber.synchronization.futures">
<title><link linkend="fiber.synchronization.futures">Futures</link></title>
<bridgehead renderas="sect4" id="fiber.synchronization.futures.h0">
<phrase id="fiber.synchronization.futures.overview"/><link linkend="fiber.synchronization.futures.overview">Overview</link>
</bridgehead>
<para>
The futures library provides a means of handling asynchronous future values,
whether those values are generated by another fiber, or on a single fiber
in response to external stimuli, or on-demand.
</para>
<para>
This is done through the provision of four class templates: <link linkend="class_future"><code>future&lt;&gt;</code></link> and
<link linkend="class_shared_future"><code>shared_future&lt;&gt;</code></link> which are used to retrieve the asynchronous
results, and <link linkend="class_promise"><code>promise&lt;&gt;</code></link> and <link linkend="class_packaged_task"><code>packaged_task&lt;&gt;</code></link> which
are used to generate the asynchronous results.
</para>
<para>
An instance of <link linkend="class_future"><code>future&lt;&gt;</code></link> holds the one and only reference
to a result. Ownership can be transferred between instances using the move
constructor or move-assignment operator, but at most one instance holds a
reference to a given asynchronous result. When the result is ready, it is
returned from <link linkend="future_get"><code>future::get()</code></link> by rvalue-reference to allow the result
to be moved or copied as appropriate for the type.
</para>
<para>
On the other hand, many instances of <link linkend="class_shared_future"><code>shared_future&lt;&gt;</code></link> may
reference the same result. Instances can be freely copied and assigned, and
<link linkend="shared_future_get"><code>shared_future::get()</code></link>
returns a <code><phrase role="keyword">const</phrase></code>
reference so that multiple calls to <link linkend="shared_future_get"><code>shared_future::get()</code></link>
are
safe. You can move an instance of <link linkend="class_future"><code>future&lt;&gt;</code></link> into an instance
of <link linkend="class_shared_future"><code>shared_future&lt;&gt;</code></link>, thus transferring ownership
of the associated asynchronous result, but not vice-versa.
</para>
<para>
<link linkend="fibers_async"><code>fibers::async()</code></link> is a simple way of running asynchronous tasks.
A call to <code><phrase role="identifier">async</phrase><phrase role="special">()</phrase></code>
spawns a fiber and returns a <link linkend="class_future"><code>future&lt;&gt;</code></link> that will deliver
the result of the fiber function.
</para>
<bridgehead renderas="sect4" id="fiber.synchronization.futures.h1">
<phrase id="fiber.synchronization.futures.creating_asynchronous_values"/><link
linkend="fiber.synchronization.futures.creating_asynchronous_values">Creating
asynchronous values</link>
</bridgehead>
<para>
You can set the value in a future with either a <link linkend="class_promise"><code>promise&lt;&gt;</code></link> or
a <link linkend="class_packaged_task"><code>packaged_task&lt;&gt;</code></link>. A <link linkend="class_packaged_task"><code>packaged_task&lt;&gt;</code></link> is
a callable object with <code><phrase role="keyword">void</phrase></code>
return that wraps a function or callable object returning the specified type.
When the <link linkend="class_packaged_task"><code>packaged_task&lt;&gt;</code></link> is invoked, it invokes the
contained function in turn, and populates a future with the contained function's
return value. This is an answer to the perennial question: <quote>How do
I return a value from a fiber?</quote> Package the function you wish to run
as a <link linkend="class_packaged_task"><code>packaged_task&lt;&gt;</code></link> and pass the packaged task to
the fiber constructor. The future retrieved from the packaged task can then
be used to obtain the return value. If the function throws an exception,
that is stored in the future in place of the return value.
</para>
<programlisting><phrase role="keyword">int</phrase> <phrase role="identifier">calculate_the_answer_to_life_the_universe_and_everything</phrase><phrase role="special">()</phrase> <phrase role="special">{</phrase>
<phrase role="keyword">return</phrase> <phrase role="number">42</phrase><phrase role="special">;</phrase>
<phrase role="special">}</phrase>
<phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">fibers</phrase><phrase role="special">::</phrase><phrase role="identifier">packaged_task</phrase><phrase role="special">&lt;</phrase><phrase role="keyword">int</phrase><phrase role="special">()&gt;</phrase> <phrase role="identifier">pt</phrase><phrase role="special">(</phrase><phrase role="identifier">calculate_the_answer_to_life_the_universe_and_everything</phrase><phrase role="special">);</phrase>
<phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">fibers</phrase><phrase role="special">::</phrase><phrase role="identifier">future</phrase><phrase role="special">&lt;</phrase><phrase role="keyword">int</phrase><phrase role="special">&gt;</phrase> <phrase role="identifier">fi</phrase><phrase role="special">=</phrase><phrase role="identifier">pt</phrase><phrase role="special">.</phrase><phrase role="identifier">get_future</phrase><phrase role="special">();</phrase>
<phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">fibers</phrase><phrase role="special">::</phrase><phrase role="identifier">fiber</phrase><phrase role="special">(</phrase><phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">move</phrase><phrase role="special">(</phrase><phrase role="identifier">pt</phrase><phrase role="special">)).</phrase><phrase role="identifier">detach</phrase><phrase role="special">();</phrase> <phrase role="comment">// launch task on a fiber</phrase>
<phrase role="identifier">fi</phrase><phrase role="special">.</phrase><phrase role="identifier">wait</phrase><phrase role="special">();</phrase> <phrase role="comment">// wait for it to finish</phrase>
<phrase role="identifier">assert</phrase><phrase role="special">(</phrase><phrase role="identifier">fi</phrase><phrase role="special">.</phrase><phrase role="identifier">is_ready</phrase><phrase role="special">());</phrase>
<phrase role="identifier">assert</phrase><phrase role="special">(</phrase><phrase role="identifier">fi</phrase><phrase role="special">.</phrase><phrase role="identifier">has_value</phrase><phrase role="special">());</phrase>
<phrase role="identifier">assert</phrase><phrase role="special">(!</phrase><phrase role="identifier">fi</phrase><phrase role="special">.</phrase><phrase role="identifier">has_exception</phrase><phrase role="special">());</phrase>
<phrase role="identifier">assert</phrase><phrase role="special">(</phrase><phrase role="identifier">fi</phrase><phrase role="special">.</phrase><phrase role="identifier">get</phrase><phrase role="special">()==</phrase><phrase role="number">42</phrase><phrase role="special">);</phrase>
</programlisting>
<para>
A <link linkend="class_promise"><code>promise&lt;&gt;</code></link> is a bit more low level: it just provides explicit
functions to store a value or an exception in the associated future. A promise
can therefore be used where the value might come from more than one possible
source.
</para>
<programlisting><phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">fibers</phrase><phrase role="special">::</phrase><phrase role="identifier">promise</phrase><phrase role="special">&lt;</phrase><phrase role="keyword">int</phrase><phrase role="special">&gt;</phrase> <phrase role="identifier">pi</phrase><phrase role="special">;</phrase>
<phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">fibers</phrase><phrase role="special">::</phrase><phrase role="identifier">future</phrase><phrase role="special">&lt;</phrase><phrase role="keyword">int</phrase><phrase role="special">&gt;</phrase> <phrase role="identifier">fi</phrase><phrase role="special">;</phrase>
<phrase role="identifier">fi</phrase><phrase role="special">=</phrase><phrase role="identifier">pi</phrase><phrase role="special">.</phrase><phrase role="identifier">get_future</phrase><phrase role="special">();</phrase>
<phrase role="identifier">pi</phrase><phrase role="special">.</phrase><phrase role="identifier">set_value</phrase><phrase role="special">(</phrase><phrase role="number">42</phrase><phrase role="special">);</phrase>
<phrase role="identifier">assert</phrase><phrase role="special">(</phrase><phrase role="identifier">fi</phrase><phrase role="special">.</phrase><phrase role="identifier">is_ready</phrase><phrase role="special">());</phrase>
<phrase role="identifier">assert</phrase><phrase role="special">(</phrase><phrase role="identifier">fi</phrase><phrase role="special">.</phrase><phrase role="identifier">has_value</phrase><phrase role="special">());</phrase>
<phrase role="identifier">assert</phrase><phrase role="special">(!</phrase><phrase role="identifier">fi</phrase><phrase role="special">.</phrase><phrase role="identifier">has_exception</phrase><phrase role="special">());</phrase>
<phrase role="identifier">assert</phrase><phrase role="special">(</phrase><phrase role="identifier">fi</phrase><phrase role="special">.</phrase><phrase role="identifier">get</phrase><phrase role="special">()==</phrase><phrase role="number">42</phrase><phrase role="special">);</phrase>
</programlisting>
<section id="fiber.synchronization.futures.future">
<title><link linkend="fiber.synchronization.futures.future">Future</link></title>
<para>
A future provides a mechanism to access the result of an asynchronous operation.
</para>
<anchor id="shared_state"/>
<bridgehead renderas="sect5" id="fiber.synchronization.futures.future.h0">
<phrase id="fiber.synchronization.futures.future.shared_state"/><link linkend="fiber.synchronization.futures.future.shared_state">shared
state</link>
</bridgehead>
<para>
Behind a <link linkend="class_promise"><code>promise&lt;&gt;</code></link> and its <link linkend="class_future"><code>future&lt;&gt;</code></link> lies
an unspecified object called their <emphasis>shared state</emphasis>. The
shared state is what will actually hold the async result (or the exception).
</para>
<para>
The shared state is instantiated along with the <link linkend="class_promise"><code>promise&lt;&gt;</code></link>.
</para>
<para>
Aside from its originating <code><phrase role="identifier">promise</phrase><phrase
role="special">&lt;&gt;</phrase></code>, a <link linkend="class_future"><code>future&lt;&gt;</code></link> holds
a unique reference to a particular shared state. However, multiple <link linkend="class_shared_future"><code>shared_future&lt;&gt;</code></link> instances
can reference the same underlying shared state.
</para>
<para>
As <link linkend="class_packaged_task"><code>packaged_task&lt;&gt;</code></link> and <link linkend="fibers_async"><code>fibers::async()</code></link> are
implemented using <link linkend="class_promise"><code>promise&lt;&gt;</code></link>, discussions of shared state
apply to them as well.
</para>
<anchor id="class_future_status"/>
<bridgehead renderas="sect5" id="fiber.synchronization.futures.future.h1">
<phrase id="fiber.synchronization.futures.future.enumeration__code__phrase_role__identifier__future_status__phrase___code_"/><link
linkend="fiber.synchronization.futures.future.enumeration__code__phrase_role__identifier__future_status__phrase___code_">Enumeration
<code><phrase role="identifier">future_status</phrase></code></link>
</bridgehead>
<para>
Timed wait-operations (<link linkend="future_wait_for"><code>future::wait_for()</code></link> and <link linkend="future_wait_until"><code>future::wait_until()</code></link>)
return the state of the future.
</para>
<programlisting><phrase role="keyword">enum</phrase> <phrase role="keyword">class</phrase> <phrase role="identifier">future_status</phrase> <phrase role="special">{</phrase>
<phrase role="identifier">ready</phrase><phrase role="special">,</phrase>
<phrase role="identifier">timeout</phrase><phrase role="special">,</phrase>
<phrase role="identifier">deferred</phrase> <phrase role="comment">// not supported yet</phrase>
<phrase role="special">};</phrase>
</programlisting>
<bridgehead renderas="sect5" id="fiber.synchronization.futures.future.h2">
<phrase id="fiber.synchronization.futures.future._code__phrase_role__identifier__ready__phrase___code_"/><link
linkend="fiber.synchronization.futures.future._code__phrase_role__identifier__ready__phrase___code_"><code><phrase
role="identifier">ready</phrase></code></link>
</bridgehead>
<variablelist>
<title></title>
<varlistentry>
<term>Effects:</term>
<listitem>
<para>
The <link linkend="shared_state">shared state</link> is ready.
</para>
</listitem>
</varlistentry>
</variablelist>
<bridgehead renderas="sect5" id="fiber.synchronization.futures.future.h3">
<phrase id="fiber.synchronization.futures.future._code__phrase_role__identifier__timeout__phrase___code_"/><link
linkend="fiber.synchronization.futures.future._code__phrase_role__identifier__timeout__phrase___code_"><code><phrase
role="identifier">timeout</phrase></code></link>
</bridgehead>
<variablelist>
<title></title>
<varlistentry>
<term>Effects:</term>
<listitem>
<para>
The <link linkend="shared_state">shared state</link> did not become
ready before timeout has passed.
</para>
</listitem>
</varlistentry>
</variablelist>
<note>
<para>
Deferred futures are not supported.
</para>
</note>
<para>
<bridgehead renderas="sect4" id="class_future_bridgehead">
<phrase id="class_future"/>
<link linkend="class_future">Template <code>future&lt;&gt;</code></link>
</bridgehead>
</para>
<para>
A <link linkend="class_future"><code>future&lt;&gt;</code></link> contains a <link linkend="shared_state">shared
state</link> which is not shared with any other future.
</para>
<programlisting><phrase role="preprocessor">#include</phrase> <phrase role="special">&lt;</phrase><phrase role="identifier">boost</phrase><phrase role="special">/</phrase><phrase role="identifier">fiber</phrase><phrase role="special">/</phrase><phrase role="identifier">future</phrase><phrase role="special">/</phrase><phrase role="identifier">future</phrase><phrase role="special">.</phrase><phrase role="identifier">hpp</phrase><phrase role="special">&gt;</phrase>
<phrase role="keyword">namespace</phrase> <phrase role="identifier">boost</phrase> <phrase role="special">{</phrase>
<phrase role="keyword">namespace</phrase> <phrase role="identifier">fibers</phrase> <phrase role="special">{</phrase>
<phrase role="keyword">template</phrase><phrase role="special">&lt;</phrase> <phrase role="keyword">typename</phrase> <phrase role="identifier">R</phrase> <phrase role="special">&gt;</phrase>
<phrase role="keyword">class</phrase> <phrase role="identifier">future</phrase> <phrase role="special">{</phrase>
<phrase role="keyword">public</phrase><phrase role="special">:</phrase>
<phrase role="identifier">future</phrase><phrase role="special">()</phrase> <phrase role="keyword">noexcept</phrase><phrase role="special">;</phrase>
<phrase role="identifier">future</phrase><phrase role="special">(</phrase> <phrase role="identifier">future</phrase> <phrase role="keyword">const</phrase><phrase role="special">&amp;</phrase> <phrase role="identifier">other</phrase><phrase role="special">)</phrase> <phrase role="special">=</phrase> <phrase role="keyword">delete</phrase><phrase role="special">;</phrase>
<phrase role="identifier">future</phrase> <phrase role="special">&amp;</phrase> <phrase role="keyword">operator</phrase><phrase role="special">=(</phrase> <phrase role="identifier">future</phrase> <phrase role="keyword">const</phrase><phrase role="special">&amp;</phrase> <phrase role="identifier">other</phrase><phrase role="special">)</phrase> <phrase role="special">=</phrase> <phrase role="keyword">delete</phrase><phrase role="special">;</phrase>
<phrase role="identifier">future</phrase><phrase role="special">(</phrase> <phrase role="identifier">future</phrase> <phrase role="special">&amp;&amp;</phrase> <phrase role="identifier">other</phrase><phrase role="special">)</phrase> <phrase role="keyword">noexcept</phrase><phrase role="special">;</phrase>
<phrase role="identifier">future</phrase> <phrase role="special">&amp;</phrase> <phrase role="keyword">operator</phrase><phrase role="special">=(</phrase> <phrase role="identifier">future</phrase> <phrase role="special">&amp;&amp;</phrase> <phrase role="identifier">other</phrase><phrase role="special">)</phrase> <phrase role="keyword">noexcept</phrase><phrase role="special">;</phrase>
<phrase role="special">~</phrase><phrase role="identifier">future</phrase><phrase role="special">();</phrase>
<phrase role="keyword">bool</phrase> <phrase role="identifier">valid</phrase><phrase role="special">()</phrase> <phrase role="keyword">const</phrase> <phrase role="keyword">noexcept</phrase><phrase role="special">;</phrase>
<phrase role="identifier">shared_future</phrase><phrase role="special">&lt;</phrase> <phrase role="identifier">R</phrase> <phrase role="special">&gt;</phrase> <phrase role="identifier">share</phrase><phrase role="special">();</phrase>
<phrase role="identifier">R</phrase> <phrase role="identifier">get</phrase><phrase role="special">();</phrase> <phrase role="comment">// member only of generic future template</phrase>
<phrase role="identifier">R</phrase> <phrase role="special">&amp;</phrase> <phrase role="identifier">get</phrase><phrase role="special">();</phrase> <phrase role="comment">// member only of future&lt; R &amp; &gt; template specialization</phrase>
<phrase role="keyword">void</phrase> <phrase role="identifier">get</phrase><phrase role="special">();</phrase> <phrase role="comment">// member only of future&lt; void &gt; template specialization</phrase>
<phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">exception_ptr</phrase> <phrase role="identifier">get_exception_ptr</phrase><phrase role="special">();</phrase>
<phrase role="keyword">void</phrase> <phrase role="identifier">wait</phrase><phrase role="special">()</phrase> <phrase role="keyword">const</phrase><phrase role="special">;</phrase>
<phrase role="keyword">template</phrase><phrase role="special">&lt;</phrase> <phrase role="keyword">class</phrase> <phrase role="identifier">Rep</phrase><phrase role="special">,</phrase> <phrase role="keyword">class</phrase> <phrase role="identifier">Period</phrase> <phrase role="special">&gt;</phrase>
<phrase role="identifier">future_status</phrase> <phrase role="identifier">wait_for</phrase><phrase role="special">(</phrase>
<phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">chrono</phrase><phrase role="special">::</phrase><phrase role="identifier">duration</phrase><phrase role="special">&lt;</phrase> <phrase role="identifier">Rep</phrase><phrase role="special">,</phrase> <phrase role="identifier">Period</phrase> <phrase role="special">&gt;</phrase> <phrase role="keyword">const</phrase><phrase role="special">&amp;</phrase> <phrase role="identifier">timeout_duration</phrase><phrase role="special">)</phrase> <phrase role="keyword">const</phrase><phrase role="special">;</phrase>
<phrase role="keyword">template</phrase><phrase role="special">&lt;</phrase> <phrase role="keyword">typename</phrase> <phrase role="identifier">Clock</phrase><phrase role="special">,</phrase> <phrase role="keyword">typename</phrase> <phrase role="identifier">Duration</phrase> <phrase role="special">&gt;</phrase>
<phrase role="identifier">future_status</phrase> <phrase role="identifier">wait_until</phrase><phrase role="special">(</phrase>
<phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">chrono</phrase><phrase role="special">::</phrase><phrase role="identifier">time_point</phrase><phrase role="special">&lt;</phrase> <phrase role="identifier">Clock</phrase><phrase role="special">,</phrase> <phrase role="identifier">Duration</phrase> <phrase role="special">&gt;</phrase> <phrase role="keyword">const</phrase><phrase role="special">&amp;</phrase> <phrase role="identifier">timeout_time</phrase><phrase role="special">)</phrase> <phrase role="keyword">const</phrase><phrase role="special">;</phrase>
<phrase role="special">};</phrase>
<phrase role="special">}}</phrase>
</programlisting>
<bridgehead renderas="sect5" id="fiber.synchronization.futures.future.h4">
<phrase id="fiber.synchronization.futures.future.default_constructor"/><link
linkend="fiber.synchronization.futures.future.default_constructor">Default
constructor</link>
</bridgehead>
<programlisting><phrase role="identifier">future</phrase><phrase role="special">()</phrase> <phrase role="keyword">noexcept</phrase><phrase role="special">;</phrase>
</programlisting>
<variablelist>
<title></title>
<varlistentry>
<term>Effects:</term>
<listitem>
<para>
Creates a future with no <link linkend="shared_state">shared state</link>.
After construction <code><phrase role="keyword">false</phrase> <phrase
role="special">==</phrase> <phrase role="identifier">valid</phrase><phrase
role="special">()</phrase></code>.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>Throws:</term>
<listitem>
<para>
Nothing.
</para>
</listitem>
</varlistentry>
</variablelist>
<bridgehead renderas="sect5" id="fiber.synchronization.futures.future.h5">
<phrase id="fiber.synchronization.futures.future.move_constructor"/><link
linkend="fiber.synchronization.futures.future.move_constructor">Move constructor</link>
</bridgehead>
<programlisting><phrase role="identifier">future</phrase><phrase role="special">(</phrase> <phrase role="identifier">future</phrase> <phrase role="special">&amp;&amp;</phrase> <phrase role="identifier">other</phrase><phrase role="special">)</phrase> <phrase role="keyword">noexcept</phrase><phrase role="special">;</phrase>
</programlisting>
<variablelist>
<title></title>
<varlistentry>
<term>Effects:</term>
<listitem>
<para>
Constructs a future with the <link linkend="shared_state">shared
state</link> of other. After construction <code><phrase role="keyword">false</phrase>
<phrase role="special">==</phrase> <phrase role="identifier">other</phrase><phrase
role="special">.</phrase><phrase role="identifier">valid</phrase><phrase
role="special">()</phrase></code>.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>Throws:</term>
<listitem>
<para>
Nothing.
</para>
</listitem>
</varlistentry>
</variablelist>
<bridgehead renderas="sect5" id="fiber.synchronization.futures.future.h6">
<phrase id="fiber.synchronization.futures.future.destructor"/><link linkend="fiber.synchronization.futures.future.destructor">Destructor</link>
</bridgehead>
<programlisting><phrase role="special">~</phrase><phrase role="identifier">future</phrase><phrase role="special">();</phrase>
</programlisting>
<variablelist>
<title></title>
<varlistentry>
<term>Effects:</term>
<listitem>
<para>
Destroys the future; ownership is abandoned.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>Note:</term>
<listitem>
<para>
<code>~future()</code> does <emphasis>not</emphasis> block the calling fiber.
</para>
</listitem>
</varlistentry>
</variablelist>
<para>
Consider a sequence such as:
</para>
<orderedlist>
<listitem>
<simpara>
instantiate <link linkend="class_promise"><code>promise&lt;&gt;</code></link>
</simpara>
</listitem>
<listitem>
<simpara>
obtain its <code><phrase role="identifier">future</phrase><phrase role="special">&lt;&gt;</phrase></code>
via <link linkend="promise_get_future"><code>promise::get_future()</code></link>
</simpara>
</listitem>
<listitem>
<simpara>
launch <link linkend="class_fiber"><code>fiber</code></link>, capturing <code><phrase role="identifier">promise</phrase><phrase
role="special">&lt;&gt;</phrase></code>
</simpara>
</listitem>
<listitem>
<simpara>
destroy <code><phrase role="identifier">future</phrase><phrase role="special">&lt;&gt;</phrase></code>
</simpara>
</listitem>
<listitem>
<simpara>
call <link linkend="promise_set_value"><code>promise::set_value()</code></link>
</simpara>
</listitem>
</orderedlist>
<para>
The final <code><phrase role="identifier">set_value</phrase><phrase role="special">()</phrase></code>
call succeeds, but the value is silently discarded: no additional <code><phrase
role="identifier">future</phrase><phrase role="special">&lt;&gt;</phrase></code>
can be obtained from that <code><phrase role="identifier">promise</phrase><phrase
role="special">&lt;&gt;</phrase></code>.
</para>
<para>
<bridgehead renderas="sect4" id="future_operator_assign_bridgehead">
<phrase id="future_operator_assign"/>
<link linkend="future_operator_assign">Member
function <code>operator=</code>()</link>
</bridgehead>
</para>
<programlisting><phrase role="identifier">future</phrase> <phrase role="special">&amp;</phrase> <phrase role="keyword">operator</phrase><phrase role="special">=(</phrase> <phrase role="identifier">future</phrase> <phrase role="special">&amp;&amp;</phrase> <phrase role="identifier">other</phrase><phrase role="special">)</phrase> <phrase role="keyword">noexcept</phrase><phrase role="special">;</phrase>
</programlisting>
<variablelist>
<title></title>
<varlistentry>
<term>Effects:</term>
<listitem>
<para>
Moves the <link linkend="shared_state">shared state</link> of other
to <code><phrase role="keyword">this</phrase></code>. After the assignment,
<code><phrase role="keyword">false</phrase> <phrase role="special">==</phrase>
<phrase role="identifier">other</phrase><phrase role="special">.</phrase><phrase
role="identifier">valid</phrase><phrase role="special">()</phrase></code>.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>Throws:</term>
<listitem>
<para>
Nothing.
</para>
</listitem>
</varlistentry>
</variablelist>
<para>
<bridgehead renderas="sect4" id="future_valid_bridgehead">
<phrase id="future_valid"/>
<link linkend="future_valid">Member function <code>valid</code>()</link>
</bridgehead>
</para>
<programlisting><phrase role="keyword">bool</phrase> <phrase role="identifier">valid</phrase><phrase role="special">()</phrase> <phrase role="keyword">const</phrase> <phrase role="keyword">noexcept</phrase><phrase role="special">;</phrase>
</programlisting>
<variablelist>
<title></title>
<varlistentry>
<term>Effects:</term>
<listitem>
<para>
Returns <code><phrase role="keyword">true</phrase></code> if future
contains a <link linkend="shared_state">shared state</link>.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>Throws:</term>
<listitem>
<para>
Nothing.
</para>
</listitem>
</varlistentry>
</variablelist>
<para>
<bridgehead renderas="sect4" id="future_share_bridgehead">
<phrase id="future_share"/>
<link linkend="future_share">Member function <code>share</code>()</link>
</bridgehead>
</para>
<programlisting><phrase role="identifier">shared_future</phrase><phrase role="special">&lt;</phrase> <phrase role="identifier">R</phrase> <phrase role="special">&gt;</phrase> <phrase role="identifier">share</phrase><phrase role="special">();</phrase>
</programlisting>
<variablelist>
<title></title>
<varlistentry>
<term>Effects:</term>
<listitem>
<para>
Move the state to a <link linkend="class_shared_future"><code>shared_future&lt;&gt;</code></link>.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>Returns:</term>
<listitem>
<para>
a <link linkend="class_shared_future"><code>shared_future&lt;&gt;</code></link> containing the <link linkend="shared_state">shared
state</link> formerly belonging to <code><phrase role="special">*</phrase><phrase
role="keyword">this</phrase></code>.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>Postcondition:</term>
<listitem>
<para>
<code><phrase role="keyword">false</phrase> <phrase role="special">==</phrase>
<phrase role="identifier">valid</phrase><phrase role="special">()</phrase></code>
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>Throws:</term>
<listitem>
<para>
<code><phrase role="identifier">future_error</phrase></code> with
error condition <code><phrase role="identifier">future_errc</phrase><phrase
role="special">::</phrase><phrase role="identifier">no_state</phrase></code>.
</para>
</listitem>
</varlistentry>
</variablelist>
<para>
<bridgehead renderas="sect4" id="future_get_bridgehead">
<phrase id="future_get"/>
<link linkend="future_get">Member function <code>get</code>()</link>
</bridgehead>
</para>
<programlisting><phrase role="identifier">R</phrase> <phrase role="identifier">get</phrase><phrase role="special">();</phrase> <phrase role="comment">// member only of generic future template</phrase>
<phrase role="identifier">R</phrase> <phrase role="special">&amp;</phrase> <phrase role="identifier">get</phrase><phrase role="special">();</phrase> <phrase role="comment">// member only of future&lt; R &amp; &gt; template specialization</phrase>
<phrase role="keyword">void</phrase> <phrase role="identifier">get</phrase><phrase role="special">();</phrase> <phrase role="comment">// member only of future&lt; void &gt; template specialization</phrase>
</programlisting>
<variablelist>
<title></title>
<varlistentry>
<term>Precondition:</term>
<listitem>
<para>
<code><phrase role="keyword">true</phrase> <phrase role="special">==</phrase>
<phrase role="identifier">valid</phrase><phrase role="special">()</phrase></code>
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>Returns:</term>
<listitem>
<para>
Waits until <link linkend="promise_set_value"><code>promise::set_value()</code></link> or <link linkend="promise_set_exception"><code>promise::set_exception()</code></link> is
called. If <link linkend="promise_set_value"><code>promise::set_value()</code></link> is called, returns
the value. If <link linkend="promise_set_exception"><code>promise::set_exception()</code></link> is called,
throws the indicated exception.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>Postcondition:</term>
<listitem>
<para>
<code><phrase role="keyword">false</phrase> <phrase role="special">==</phrase>
<phrase role="identifier">valid</phrase><phrase role="special">()</phrase></code>
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>Throws:</term>
<listitem>
<para>
<code><phrase role="identifier">future_error</phrase></code> with
error condition <code><phrase role="identifier">future_errc</phrase><phrase
role="special">::</phrase><phrase role="identifier">no_state</phrase></code>,
<code><phrase role="identifier">future_errc</phrase><phrase role="special">::</phrase><phrase
role="identifier">broken_promise</phrase></code>. Any exception passed
to <code><phrase role="identifier">promise</phrase><phrase role="special">::</phrase><phrase
role="identifier">set_exception</phrase><phrase role="special">()</phrase></code>.
</para>
</listitem>
</varlistentry>
</variablelist>
<para>
<bridgehead renderas="sect4" id="future_get_exception_ptr_bridgehead">
<phrase id="future_get_exception_ptr"/>
<link linkend="future_get_exception_ptr">Member
function <code>get_exception_ptr</code>()</link>
</bridgehead>
</para>
<programlisting><phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">exception_ptr</phrase> <phrase role="identifier">get_exception_ptr</phrase><phrase role="special">();</phrase>
</programlisting>
<variablelist>
<title></title>
<varlistentry>
<term>Precondition:</term>
<listitem>
<para>
<code><phrase role="keyword">true</phrase> <phrase role="special">==</phrase>
<phrase role="identifier">valid</phrase><phrase role="special">()</phrase></code>
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>Returns:</term>
<listitem>
<para>
Waits until <link linkend="promise_set_value"><code>promise::set_value()</code></link> or <link linkend="promise_set_exception"><code>promise::set_exception()</code></link> is
called. If <code><phrase role="identifier">set_value</phrase><phrase
role="special">()</phrase></code> is called, returns a default-constructed
<code><phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase
role="identifier">exception_ptr</phrase></code>. If <code><phrase
role="identifier">set_exception</phrase><phrase role="special">()</phrase></code>
is called, returns the passed <code><phrase role="identifier">std</phrase><phrase
role="special">::</phrase><phrase role="identifier">exception_ptr</phrase></code>.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>Throws:</term>
<listitem>
<para>
<code><phrase role="identifier">future_error</phrase></code> with
error condition <code><phrase role="identifier">future_errc</phrase><phrase
role="special">::</phrase><phrase role="identifier">no_state</phrase></code>.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>Note:</term>
<listitem>
<para>
<code><phrase role="identifier">get_exception_ptr</phrase><phrase
role="special">()</phrase></code> does <emphasis>not</emphasis> invalidate
the <code>future</code>. After calling <code><phrase role="identifier">get_exception_ptr</phrase><phrase
role="special">()</phrase></code>, you may still call <link linkend="future_get"><code>future::get()</code></link>.
</para>
</listitem>
</varlistentry>
</variablelist>
<para>
<bridgehead renderas="sect4" id="future_wait_bridgehead">
<phrase id="future_wait"/>
<link linkend="future_wait">Member function <code>wait</code>()</link>
</bridgehead>
</para>
<programlisting><phrase role="keyword">void</phrase> <phrase role="identifier">wait</phrase><phrase role="special">();</phrase>
</programlisting>
<variablelist>
<title></title>
<varlistentry>
<term>Effects:</term>
<listitem>
<para>
Waits until <link linkend="promise_set_value"><code>promise::set_value()</code></link> or <link linkend="promise_set_exception"><code>promise::set_exception()</code></link> is
called.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>Throws:</term>
<listitem>
<para>
<code><phrase role="identifier">future_error</phrase></code> with
error condition <code><phrase role="identifier">future_errc</phrase><phrase
role="special">::</phrase><phrase role="identifier">no_state</phrase></code>.
</para>
</listitem>
</varlistentry>
</variablelist>
<para>
<bridgehead renderas="sect4" id="future_wait_for_bridgehead">
<phrase id="future_wait_for"/>
<link linkend="future_wait_for">Templated member
function <code>wait_for</code>()</link>
</bridgehead>
</para>
<programlisting><phrase role="keyword">template</phrase><phrase role="special">&lt;</phrase> <phrase role="keyword">class</phrase> <phrase role="identifier">Rep</phrase><phrase role="special">,</phrase> <phrase role="keyword">class</phrase> <phrase role="identifier">Period</phrase> <phrase role="special">&gt;</phrase>
<phrase role="identifier">future_status</phrase> <phrase role="identifier">wait_for</phrase><phrase role="special">(</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">chrono</phrase><phrase role="special">::</phrase><phrase role="identifier">duration</phrase><phrase role="special">&lt;</phrase> <phrase role="identifier">Rep</phrase><phrase role="special">,</phrase> <phrase role="identifier">Period</phrase> <phrase role="special">&gt;</phrase> <phrase role="keyword">const</phrase><phrase role="special">&amp;</phrase> <phrase role="identifier">timeout_duration</phrase><phrase role="special">)</phrase> <phrase role="keyword">const</phrase><phrase role="special">;</phrase>
</programlisting>
<variablelist>
<title></title>
<varlistentry>
<term>Effects:</term>
<listitem>
<para>
Waits until <link linkend="promise_set_value"><code>promise::set_value()</code></link> or <link linkend="promise_set_exception"><code>promise::set_exception()</code></link> is
called, or <code><phrase role="identifier">timeout_duration</phrase></code>
has passed.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>Result:</term>
<listitem>
<para>
A <code><phrase role="identifier">future_status</phrase></code> is
returned indicating the reason for returning.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>Throws:</term>
<listitem>
<para>
<code><phrase role="identifier">future_error</phrase></code> with
error condition <code><phrase role="identifier">future_errc</phrase><phrase
role="special">::</phrase><phrase role="identifier">no_state</phrase></code>
or timeout-related exceptions.
</para>
</listitem>
</varlistentry>
</variablelist>
<para>
<bridgehead renderas="sect4" id="future_wait_until_bridgehead">
<phrase id="future_wait_until"/>
<link linkend="future_wait_until">Templated
member function <code>wait_until</code>()</link>
</bridgehead>
</para>
<programlisting><phrase role="keyword">template</phrase><phrase role="special">&lt;</phrase> <phrase role="keyword">typename</phrase> <phrase role="identifier">Clock</phrase><phrase role="special">,</phrase> <phrase role="keyword">typename</phrase> <phrase role="identifier">Duration</phrase> <phrase role="special">&gt;</phrase>
<phrase role="identifier">future_status</phrase> <phrase role="identifier">wait_until</phrase><phrase role="special">(</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">chrono</phrase><phrase role="special">::</phrase><phrase role="identifier">time_point</phrase><phrase role="special">&lt;</phrase> <phrase role="identifier">Clock</phrase><phrase role="special">,</phrase> <phrase role="identifier">Duration</phrase> <phrase role="special">&gt;</phrase> <phrase role="keyword">const</phrase><phrase role="special">&amp;</phrase> <phrase role="identifier">timeout_time</phrase><phrase role="special">)</phrase> <phrase role="keyword">const</phrase><phrase role="special">;</phrase>
</programlisting>
<variablelist>
<title></title>
<varlistentry>
<term>Effects:</term>
<listitem>
<para>
Waits until <link linkend="promise_set_value"><code>promise::set_value()</code></link> or <link linkend="promise_set_exception"><code>promise::set_exception()</code></link> is
called, or <code><phrase role="identifier">timeout_time</phrase></code>
has passed.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>Result:</term>
<listitem>
<para>
A <code><phrase role="identifier">future_status</phrase></code> is
returned indicating the reason for returning.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>Throws:</term>
<listitem>
<para>
<code><phrase role="identifier">future_error</phrase></code> with
error condition <code><phrase role="identifier">future_errc</phrase><phrase
role="special">::</phrase><phrase role="identifier">no_state</phrase></code>
or timeout-related exceptions.
</para>
</listitem>
</varlistentry>
</variablelist>
<para>
<bridgehead renderas="sect4" id="class_shared_future_bridgehead">
<phrase id="class_shared_future"/>
<link linkend="class_shared_future">Template
<code>shared_future&lt;&gt;</code></link>
</bridgehead>
</para>
<para>
A <link linkend="class_shared_future"><code>shared_future&lt;&gt;</code></link> contains a <link linkend="shared_state">shared
state</link> which might be shared with other <link linkend="class_shared_future"><code>shared_future&lt;&gt;</code></link> instances.
</para>
<programlisting><phrase role="preprocessor">#include</phrase> <phrase role="special">&lt;</phrase><phrase role="identifier">boost</phrase><phrase role="special">/</phrase><phrase role="identifier">fiber</phrase><phrase role="special">/</phrase><phrase role="identifier">future</phrase><phrase role="special">/</phrase><phrase role="identifier">future</phrase><phrase role="special">.</phrase><phrase role="identifier">hpp</phrase><phrase role="special">&gt;</phrase>
<phrase role="keyword">namespace</phrase> <phrase role="identifier">boost</phrase> <phrase role="special">{</phrase>
<phrase role="keyword">namespace</phrase> <phrase role="identifier">fibers</phrase> <phrase role="special">{</phrase>
<phrase role="keyword">template</phrase><phrase role="special">&lt;</phrase> <phrase role="keyword">typename</phrase> <phrase role="identifier">R</phrase> <phrase role="special">&gt;</phrase>
<phrase role="keyword">class</phrase> <phrase role="identifier">shared_future</phrase> <phrase role="special">{</phrase>
<phrase role="keyword">public</phrase><phrase role="special">:</phrase>
<phrase role="identifier">shared_future</phrase><phrase role="special">()</phrase> <phrase role="keyword">noexcept</phrase><phrase role="special">;</phrase>
<phrase role="special">~</phrase><phrase role="identifier">shared_future</phrase><phrase role="special">();</phrase>
<phrase role="identifier">shared_future</phrase><phrase role="special">(</phrase> <phrase role="identifier">shared_future</phrase> <phrase role="keyword">const</phrase><phrase role="special">&amp;</phrase> <phrase role="identifier">other</phrase><phrase role="special">);</phrase>
<phrase role="identifier">shared_future</phrase><phrase role="special">(</phrase> <phrase role="identifier">future</phrase><phrase role="special">&lt;</phrase> <phrase role="identifier">R</phrase> <phrase role="special">&gt;</phrase> <phrase role="special">&amp;&amp;</phrase> <phrase role="identifier">other</phrase><phrase role="special">)</phrase> <phrase role="keyword">noexcept</phrase><phrase role="special">;</phrase>
<phrase role="identifier">shared_future</phrase><phrase role="special">(</phrase> <phrase role="identifier">shared_future</phrase> <phrase role="special">&amp;&amp;</phrase> <phrase role="identifier">other</phrase><phrase role="special">)</phrase> <phrase role="keyword">noexcept</phrase><phrase role="special">;</phrase>
<phrase role="identifier">shared_future</phrase> <phrase role="special">&amp;</phrase> <phrase role="keyword">operator</phrase><phrase role="special">=(</phrase> <phrase role="identifier">shared_future</phrase> <phrase role="special">&amp;&amp;</phrase> <phrase role="identifier">other</phrase><phrase role="special">)</phrase> <phrase role="keyword">noexcept</phrase><phrase role="special">;</phrase>
<phrase role="identifier">shared_future</phrase> <phrase role="special">&amp;</phrase> <phrase role="keyword">operator</phrase><phrase role="special">=(</phrase> <phrase role="identifier">future</phrase><phrase role="special">&lt;</phrase> <phrase role="identifier">R</phrase> <phrase role="special">&gt;</phrase> <phrase role="special">&amp;&amp;</phrase> <phrase role="identifier">other</phrase><phrase role="special">)</phrase> <phrase role="keyword">noexcept</phrase><phrase role="special">;</phrase>
<phrase role="identifier">shared_future</phrase> <phrase role="special">&amp;</phrase> <phrase role="keyword">operator</phrase><phrase role="special">=(</phrase> <phrase role="identifier">shared_future</phrase> <phrase role="keyword">const</phrase><phrase role="special">&amp;</phrase> <phrase role="identifier">other</phrase><phrase role="special">)</phrase> <phrase role="keyword">noexcept</phrase><phrase role="special">;</phrase>
<phrase role="keyword">bool</phrase> <phrase role="identifier">valid</phrase><phrase role="special">()</phrase> <phrase role="keyword">const</phrase> <phrase role="keyword">noexcept</phrase><phrase role="special">;</phrase>
<phrase role="identifier">R</phrase> <phrase role="keyword">const</phrase><phrase role="special">&amp;</phrase> <phrase role="identifier">get</phrase><phrase role="special">();</phrase> <phrase role="comment">// member only of generic shared_future template</phrase>
<phrase role="identifier">R</phrase> <phrase role="special">&amp;</phrase> <phrase role="identifier">get</phrase><phrase role="special">();</phrase> <phrase role="comment">// member only of shared_future&lt; R &amp; &gt; template specialization</phrase>
<phrase role="keyword">void</phrase> <phrase role="identifier">get</phrase><phrase role="special">();</phrase> <phrase role="comment">// member only of shared_future&lt; void &gt; template specialization</phrase>
<phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">exception_ptr</phrase> <phrase role="identifier">get_exception_ptr</phrase><phrase role="special">();</phrase>
<phrase role="keyword">void</phrase> <phrase role="identifier">wait</phrase><phrase role="special">()</phrase> <phrase role="keyword">const</phrase><phrase role="special">;</phrase>
<phrase role="keyword">template</phrase><phrase role="special">&lt;</phrase> <phrase role="keyword">class</phrase> <phrase role="identifier">Rep</phrase><phrase role="special">,</phrase> <phrase role="keyword">class</phrase> <phrase role="identifier">Period</phrase> <phrase role="special">&gt;</phrase>
<phrase role="identifier">future_status</phrase> <phrase role="identifier">wait_for</phrase><phrase role="special">(</phrase>
<phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">chrono</phrase><phrase role="special">::</phrase><phrase role="identifier">duration</phrase><phrase role="special">&lt;</phrase> <phrase role="identifier">Rep</phrase><phrase role="special">,</phrase> <phrase role="identifier">Period</phrase> <phrase role="special">&gt;</phrase> <phrase role="keyword">const</phrase><phrase role="special">&amp;</phrase> <phrase role="identifier">timeout_duration</phrase><phrase role="special">)</phrase> <phrase role="keyword">const</phrase><phrase role="special">;</phrase>
<phrase role="keyword">template</phrase><phrase role="special">&lt;</phrase> <phrase role="keyword">typename</phrase> <phrase role="identifier">Clock</phrase><phrase role="special">,</phrase> <phrase role="keyword">typename</phrase> <phrase role="identifier">Duration</phrase> <phrase role="special">&gt;</phrase>
<phrase role="identifier">future_status</phrase> <phrase role="identifier">wait_until</phrase><phrase role="special">(</phrase>
<phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">chrono</phrase><phrase role="special">::</phrase><phrase role="identifier">time_point</phrase><phrase role="special">&lt;</phrase> <phrase role="identifier">Clock</phrase><phrase role="special">,</phrase> <phrase role="identifier">Duration</phrase> <phrase role="special">&gt;</phrase> <phrase role="keyword">const</phrase><phrase role="special">&amp;</phrase> <phrase role="identifier">timeout_time</phrase><phrase role="special">)</phrase> <phrase role="keyword">const</phrase><phrase role="special">;</phrase>
<phrase role="special">};</phrase>
<phrase role="special">}}</phrase>
</programlisting>
<bridgehead renderas="sect5" id="fiber.synchronization.futures.future.h7">
<phrase id="fiber.synchronization.futures.future.default_constructor0"/><link
linkend="fiber.synchronization.futures.future.default_constructor0">Default
constructor</link>
</bridgehead>
<programlisting><phrase role="identifier">shared_future</phrase><phrase role="special">();</phrase>
</programlisting>
<variablelist>
<title></title>
<varlistentry>
<term>Effects:</term>
<listitem>
<para>
Creates a shared_future with no <link linkend="shared_state">shared
state</link>. After construction <code><phrase role="keyword">false</phrase>
<phrase role="special">==</phrase> <phrase role="identifier">valid</phrase><phrase
role="special">()</phrase></code>.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>Throws:</term>
<listitem>
<para>
Nothing.
</para>
</listitem>
</varlistentry>
</variablelist>
<bridgehead renderas="sect5" id="fiber.synchronization.futures.future.h8">
<phrase id="fiber.synchronization.futures.future.move_constructor0"/><link
linkend="fiber.synchronization.futures.future.move_constructor0">Move constructor</link>
</bridgehead>
<programlisting><phrase role="identifier">shared_future</phrase><phrase role="special">(</phrase> <phrase role="identifier">future</phrase><phrase role="special">&lt;</phrase> <phrase role="identifier">R</phrase> <phrase role="special">&gt;</phrase> <phrase role="special">&amp;&amp;</phrase> <phrase role="identifier">other</phrase><phrase role="special">)</phrase> <phrase role="keyword">noexcept</phrase><phrase role="special">;</phrase>
<phrase role="identifier">shared_future</phrase><phrase role="special">(</phrase> <phrase role="identifier">shared_future</phrase> <phrase role="special">&amp;&amp;</phrase> <phrase role="identifier">other</phrase><phrase role="special">)</phrase> <phrase role="keyword">noexcept</phrase><phrase role="special">;</phrase>
</programlisting>
<variablelist>
<title></title>
<varlistentry>
<term>Effects:</term>
<listitem>
<para>
Constructs a shared_future with the <link linkend="shared_state">shared
state</link> of other. After construction <code><phrase role="keyword">false</phrase>
<phrase role="special">==</phrase> <phrase role="identifier">other</phrase><phrase
role="special">.</phrase><phrase role="identifier">valid</phrase><phrase
role="special">()</phrase></code>.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>Throws:</term>
<listitem>
<para>
Nothing.
</para>
</listitem>
</varlistentry>
</variablelist>
<bridgehead renderas="sect5" id="fiber.synchronization.futures.future.h9">
<phrase id="fiber.synchronization.futures.future.copy_constructor"/><link
linkend="fiber.synchronization.futures.future.copy_constructor">Copy constructor</link>
</bridgehead>
<programlisting><phrase role="identifier">shared_future</phrase><phrase role="special">(</phrase> <phrase role="identifier">shared_future</phrase> <phrase role="keyword">const</phrase><phrase role="special">&amp;</phrase> <phrase role="identifier">other</phrase><phrase role="special">)</phrase> <phrase role="keyword">noexcept</phrase><phrase role="special">;</phrase>
</programlisting>
<variablelist>
<title></title>
<varlistentry>
<term>Effects:</term>
<listitem>
<para>
Constructs a shared_future with the <link linkend="shared_state">shared
state</link> of other. After construction <code><phrase role="identifier">other</phrase><phrase
role="special">.</phrase><phrase role="identifier">valid</phrase><phrase
role="special">()</phrase></code> is unchanged.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>Throws:</term>
<listitem>
<para>
Nothing.
</para>
</listitem>
</varlistentry>
</variablelist>
<bridgehead renderas="sect5" id="fiber.synchronization.futures.future.h10">
<phrase id="fiber.synchronization.futures.future.destructor0"/><link linkend="fiber.synchronization.futures.future.destructor0">Destructor</link>
</bridgehead>
<programlisting><phrase role="special">~</phrase><phrase role="identifier">shared_future</phrase><phrase role="special">();</phrase>
</programlisting>
<variablelist>
<title></title>
<varlistentry>
<term>Effects:</term>
<listitem>
<para>
Destroys the shared_future; ownership is abandoned if not shared.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>Note:</term>
<listitem>
<para>
<code>~shared_future()</code> does <emphasis>not</emphasis> block the calling fiber.
</para>
</listitem>
</varlistentry>
</variablelist>
<para>
<bridgehead renderas="sect4" id="shared_future_operator_assign_bridgehead">
<phrase id="shared_future_operator_assign"/>
<link linkend="shared_future_operator_assign">Member
function <code>operator=</code>()</link>
</bridgehead>
</para>
<programlisting><phrase role="identifier">shared_future</phrase> <phrase role="special">&amp;</phrase> <phrase role="keyword">operator</phrase><phrase role="special">=(</phrase> <phrase role="identifier">future</phrase><phrase role="special">&lt;</phrase> <phrase role="identifier">R</phrase> <phrase role="special">&gt;</phrase> <phrase role="special">&amp;&amp;</phrase> <phrase role="identifier">other</phrase><phrase role="special">)</phrase> <phrase role="keyword">noexcept</phrase><phrase role="special">;</phrase>
<phrase role="identifier">shared_future</phrase> <phrase role="special">&amp;</phrase> <phrase role="keyword">operator</phrase><phrase role="special">=(</phrase> <phrase role="identifier">shared_future</phrase> <phrase role="special">&amp;&amp;</phrase> <phrase role="identifier">other</phrase><phrase role="special">)</phrase> <phrase role="keyword">noexcept</phrase><phrase role="special">;</phrase>
<phrase role="identifier">shared_future</phrase> <phrase role="special">&amp;</phrase> <phrase role="keyword">operator</phrase><phrase role="special">=(</phrase> <phrase role="identifier">shared_future</phrase> <phrase role="keyword">const</phrase><phrase role="special">&amp;</phrase> <phrase role="identifier">other</phrase><phrase role="special">)</phrase> <phrase role="keyword">noexcept</phrase><phrase role="special">;</phrase>
</programlisting>
<variablelist>
<title></title>
<varlistentry>
<term>Effects:</term>
<listitem>
<para>
Moves or copies the <link linkend="shared_state">shared state</link>
of other to <code><phrase role="keyword">this</phrase></code>. After
the assignment, the state of <code><phrase role="identifier">other</phrase><phrase
role="special">.</phrase><phrase role="identifier">valid</phrase><phrase
role="special">()</phrase></code> depends on which overload was invoked:
unchanged for the overload accepting <code><phrase role="identifier">shared_future</phrase>
<phrase role="keyword">const</phrase><phrase role="special">&amp;</phrase></code>,
otherwise <code><phrase role="keyword">false</phrase></code>.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>Throws:</term>
<listitem>
<para>
Nothing.
</para>
</listitem>
</varlistentry>
</variablelist>
<para>
<bridgehead renderas="sect4" id="shared_future_valid_bridgehead">
<phrase id="shared_future_valid"/>
<link linkend="shared_future_valid">Member
function <code>valid</code>()</link>
</bridgehead>
</para>
<programlisting><phrase role="keyword">bool</phrase> <phrase role="identifier">valid</phrase><phrase role="special">()</phrase> <phrase role="keyword">const</phrase> <phrase role="keyword">noexcept</phrase><phrase role="special">;</phrase>
</programlisting>
<variablelist>
<title></title>
<varlistentry>
<term>Effects:</term>
<listitem>
<para>
Returns <code><phrase role="keyword">true</phrase></code> if shared_future
contains a <link linkend="shared_state">shared state</link>.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>Throws:</term>
<listitem>
<para>
Nothing.
</para>
</listitem>
</varlistentry>
</variablelist>
<para>
<bridgehead renderas="sect4" id="shared_future_get_bridgehead">
<phrase id="shared_future_get"/>
<link linkend="shared_future_get">Member function
<code>get</code>()</link>
</bridgehead>
</para>
<programlisting><phrase role="identifier">R</phrase> <phrase role="keyword">const</phrase><phrase role="special">&amp;</phrase> <phrase role="identifier">get</phrase><phrase role="special">();</phrase> <phrase role="comment">// member only of generic shared_future template</phrase>
<phrase role="identifier">R</phrase> <phrase role="special">&amp;</phrase> <phrase role="identifier">get</phrase><phrase role="special">();</phrase> <phrase role="comment">// member only of shared_future&lt; R &amp; &gt; template specialization</phrase>
<phrase role="keyword">void</phrase> <phrase role="identifier">get</phrase><phrase role="special">();</phrase> <phrase role="comment">// member only of shared_future&lt; void &gt; template specialization</phrase>
</programlisting>
<variablelist>
<title></title>
<varlistentry>
<term>Precondition:</term>
<listitem>
<para>
<code><phrase role="keyword">true</phrase> <phrase role="special">==</phrase>
<phrase role="identifier">valid</phrase><phrase role="special">()</phrase></code>
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>Returns:</term>
<listitem>
<para>
Waits until <link linkend="promise_set_value"><code>promise::set_value()</code></link> or <link linkend="promise_set_exception"><code>promise::set_exception()</code></link> is
called. If <link linkend="promise_set_value"><code>promise::set_value()</code></link> is called, returns
the value. If <link linkend="promise_set_exception"><code>promise::set_exception()</code></link> is called,
throws the indicated exception.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>Postcondition:</term>
<listitem>
<para>
<code><phrase role="keyword">false</phrase> <phrase role="special">==</phrase>
<phrase role="identifier">valid</phrase><phrase role="special">()</phrase></code>
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>Throws:</term>
<listitem>
<para>
<code><phrase role="identifier">future_error</phrase></code> with
error condition <code><phrase role="identifier">future_errc</phrase><phrase
role="special">::</phrase><phrase role="identifier">no_state</phrase></code>,
<code><phrase role="identifier">future_errc</phrase><phrase role="special">::</phrase><phrase
role="identifier">broken_promise</phrase></code>. Any exception passed
to <code><phrase role="identifier">promise</phrase><phrase role="special">::</phrase><phrase
role="identifier">set_exception</phrase><phrase role="special">()</phrase></code>.
</para>
</listitem>
</varlistentry>
</variablelist>
<para>
<bridgehead renderas="sect4" id="shared_future_get_exception_ptr_bridgehead">
<phrase id="shared_future_get_exception_ptr"/>
<link linkend="shared_future_get_exception_ptr">Member
function <code>get_exception_ptr</code>()</link>
</bridgehead>
</para>
<programlisting><phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">exception_ptr</phrase> <phrase role="identifier">get_exception_ptr</phrase><phrase role="special">();</phrase>
</programlisting>
<variablelist>
<title></title>
<varlistentry>
<term>Precondition:</term>
<listitem>
<para>
<code><phrase role="keyword">true</phrase> <phrase role="special">==</phrase>
<phrase role="identifier">valid</phrase><phrase role="special">()</phrase></code>
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>Returns:</term>
<listitem>
<para>
Waits until <link linkend="promise_set_value"><code>promise::set_value()</code></link> or <link linkend="promise_set_exception"><code>promise::set_exception()</code></link> is
called. If <code><phrase role="identifier">set_value</phrase><phrase
role="special">()</phrase></code> is called, returns a default-constructed
<code><phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase
role="identifier">exception_ptr</phrase></code>. If <code><phrase
role="identifier">set_exception</phrase><phrase role="special">()</phrase></code>
is called, returns the passed <code><phrase role="identifier">std</phrase><phrase
role="special">::</phrase><phrase role="identifier">exception_ptr</phrase></code>.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>Throws:</term>
<listitem>
<para>
<code><phrase role="identifier">future_error</phrase></code> with
error condition <code><phrase role="identifier">future_errc</phrase><phrase
role="special">::</phrase><phrase role="identifier">no_state</phrase></code>.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>Note:</term>
<listitem>
<para>
<code><phrase role="identifier">get_exception_ptr</phrase><phrase
role="special">()</phrase></code> does <emphasis>not</emphasis> invalidate
the <code>shared_future</code>. After calling <code><phrase role="identifier">get_exception_ptr</phrase><phrase
role="special">()</phrase></code>, you may still call <link linkend="shared_future_get"><code>shared_future::get()</code></link>.
</para>
</listitem>
</varlistentry>
</variablelist>
<para>
<bridgehead renderas="sect4" id="shared_future_wait_bridgehead">
<phrase id="shared_future_wait"/>
<link linkend="shared_future_wait">Member
function <code>wait</code>()</link>
</bridgehead>
</para>
<programlisting><phrase role="keyword">void</phrase> <phrase role="identifier">wait</phrase><phrase role="special">();</phrase>
</programlisting>
<variablelist>
<title></title>
<varlistentry>
<term>Effects:</term>
<listitem>
<para>
Waits until <link linkend="promise_set_value"><code>promise::set_value()</code></link> or <link linkend="promise_set_exception"><code>promise::set_exception()</code></link> is
called.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>Throws:</term>
<listitem>
<para>
<code><phrase role="identifier">future_error</phrase></code> with
error condition <code><phrase role="identifier">future_errc</phrase><phrase
role="special">::</phrase><phrase role="identifier">no_state</phrase></code>.
</para>
</listitem>
</varlistentry>
</variablelist>
<para>
<bridgehead renderas="sect4" id="shared_future_wait_for_bridgehead">
<phrase id="shared_future_wait_for"/>
<link linkend="shared_future_wait_for">Templated
member function <code>wait_for</code>()</link>
</bridgehead>
</para>
<programlisting><phrase role="keyword">template</phrase><phrase role="special">&lt;</phrase> <phrase role="keyword">class</phrase> <phrase role="identifier">Rep</phrase><phrase role="special">,</phrase> <phrase role="keyword">class</phrase> <phrase role="identifier">Period</phrase> <phrase role="special">&gt;</phrase>
<phrase role="identifier">future_status</phrase> <phrase role="identifier">wait_for</phrase><phrase role="special">(</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">chrono</phrase><phrase role="special">::</phrase><phrase role="identifier">duration</phrase><phrase role="special">&lt;</phrase> <phrase role="identifier">Rep</phrase><phrase role="special">,</phrase> <phrase role="identifier">Period</phrase> <phrase role="special">&gt;</phrase> <phrase role="keyword">const</phrase><phrase role="special">&amp;</phrase> <phrase role="identifier">timeout_duration</phrase><phrase role="special">)</phrase> <phrase role="keyword">const</phrase><phrase role="special">;</phrase>
</programlisting>
<variablelist>
<title></title>
<varlistentry>
<term>Effects:</term>
<listitem>
<para>
Waits until <link linkend="promise_set_value"><code>promise::set_value()</code></link> or <link linkend="promise_set_exception"><code>promise::set_exception()</code></link> is
called, or <code><phrase role="identifier">timeout_duration</phrase></code>
has passed.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>Result:</term>
<listitem>
<para>
A <code><phrase role="identifier">future_status</phrase></code> is
returned indicating the reason for returning.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>Throws:</term>
<listitem>
<para>
<code><phrase role="identifier">future_error</phrase></code> with
error condition <code><phrase role="identifier">future_errc</phrase><phrase
role="special">::</phrase><phrase role="identifier">no_state</phrase></code>
or timeout-related exceptions.
</para>
</listitem>
</varlistentry>
</variablelist>
<para>
<bridgehead renderas="sect4" id="shared_future_wait_until_bridgehead">
<phrase id="shared_future_wait_until"/>
<link linkend="shared_future_wait_until">Templated
member function <code>wait_until</code>()</link>
</bridgehead>
</para>
<programlisting><phrase role="keyword">template</phrase><phrase role="special">&lt;</phrase> <phrase role="keyword">typename</phrase> <phrase role="identifier">Clock</phrase><phrase role="special">,</phrase> <phrase role="keyword">typename</phrase> <phrase role="identifier">Duration</phrase> <phrase role="special">&gt;</phrase>
<phrase role="identifier">future_status</phrase> <phrase role="identifier">wait_until</phrase><phrase role="special">(</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">chrono</phrase><phrase role="special">::</phrase><phrase role="identifier">time_point</phrase><phrase role="special">&lt;</phrase> <phrase role="identifier">Clock</phrase><phrase role="special">,</phrase> <phrase role="identifier">Duration</phrase> <phrase role="special">&gt;</phrase> <phrase role="keyword">const</phrase><phrase role="special">&amp;</phrase> <phrase role="identifier">timeout_time</phrase><phrase role="special">)</phrase> <phrase role="keyword">const</phrase><phrase role="special">;</phrase>
</programlisting>
<variablelist>
<title></title>
<varlistentry>
<term>Effects:</term>
<listitem>
<para>
Waits until <link linkend="promise_set_value"><code>promise::set_value()</code></link> or <link linkend="promise_set_exception"><code>promise::set_exception()</code></link> is
called, or <code><phrase role="identifier">timeout_time</phrase></code>
has passed.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>Result:</term>
<listitem>
<para>
A <code><phrase role="identifier">future_status</phrase></code> is
returned indicating the reason for returning.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>Throws:</term>
<listitem>
<para>
<code><phrase role="identifier">future_error</phrase></code> with
error condition <code><phrase role="identifier">future_errc</phrase><phrase
role="special">::</phrase><phrase role="identifier">no_state</phrase></code>
or timeout-related exceptions.
</para>
</listitem>
</varlistentry>
</variablelist>
<para>
<bridgehead renderas="sect4" id="fibers_async_bridgehead">
<phrase id="fibers_async"/>
<link linkend="fibers_async">Non-member function <code>fibers::async()</code></link>
</bridgehead>
</para>
<programlisting><phrase role="preprocessor">#include</phrase> <phrase role="special">&lt;</phrase><phrase role="identifier">boost</phrase><phrase role="special">/</phrase><phrase role="identifier">fiber</phrase><phrase role="special">/</phrase><phrase role="identifier">future</phrase><phrase role="special">/</phrase><phrase role="identifier">async</phrase><phrase role="special">.</phrase><phrase role="identifier">hpp</phrase><phrase role="special">&gt;</phrase>
<phrase role="keyword">namespace</phrase> <phrase role="identifier">boost</phrase> <phrase role="special">{</phrase>
<phrase role="keyword">namespace</phrase> <phrase role="identifier">fibers</phrase> <phrase role="special">{</phrase>
<phrase role="keyword">template</phrase><phrase role="special">&lt;</phrase> <phrase role="keyword">class</phrase> <phrase role="identifier">Function</phrase><phrase role="special">,</phrase> <phrase role="keyword">class</phrase> <phrase role="special">...</phrase> <phrase role="identifier">Args</phrase> <phrase role="special">&gt;</phrase>
<phrase role="identifier">future</phrase><phrase role="special">&lt;</phrase>
<phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">result_of_t</phrase><phrase role="special">&lt;</phrase>
<phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">decay_t</phrase><phrase role="special">&lt;</phrase> <phrase role="identifier">Function</phrase> <phrase role="special">&gt;(</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">decay_t</phrase><phrase role="special">&lt;</phrase> <phrase role="identifier">Args</phrase> <phrase role="special">&gt;</phrase> <phrase role="special">...</phrase> <phrase role="special">)</phrase>
<phrase role="special">&gt;</phrase>
<phrase role="special">&gt;</phrase>
<phrase role="identifier">async</phrase><phrase role="special">(</phrase> <phrase role="identifier">Function</phrase> <phrase role="special">&amp;&amp;</phrase> <phrase role="identifier">fn</phrase><phrase role="special">,</phrase> <phrase role="identifier">Args</phrase> <phrase role="special">&amp;&amp;</phrase> <phrase role="special">...</phrase> <phrase role="identifier">args</phrase><phrase role="special">);</phrase>
<phrase role="keyword">template</phrase><phrase role="special">&lt;</phrase> <phrase role="keyword">class</phrase> <phrase role="identifier">Function</phrase><phrase role="special">,</phrase> <phrase role="keyword">class</phrase> <phrase role="special">...</phrase> <phrase role="identifier">Args</phrase> <phrase role="special">&gt;</phrase>
<phrase role="identifier">future</phrase><phrase role="special">&lt;</phrase>
<phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">result_of_t</phrase><phrase role="special">&lt;</phrase>
<phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">decay_t</phrase><phrase role="special">&lt;</phrase> <phrase role="identifier">Function</phrase> <phrase role="special">&gt;(</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">decay_t</phrase><phrase role="special">&lt;</phrase> <phrase role="identifier">Args</phrase> <phrase role="special">&gt;</phrase> <phrase role="special">...</phrase> <phrase role="special">)</phrase>
<phrase role="special">&gt;</phrase>
<phrase role="special">&gt;</phrase>
<phrase role="identifier">async</phrase><phrase role="special">(</phrase> <link linkend="class_launch"><code><phrase role="identifier">launch</phrase></code></link> <phrase role="identifier">policy</phrase><phrase role="special">,</phrase> <phrase role="identifier">Function</phrase> <phrase role="special">&amp;&amp;</phrase> <phrase role="identifier">fn</phrase><phrase role="special">,</phrase> <phrase role="identifier">Args</phrase> <phrase role="special">&amp;&amp;</phrase> <phrase role="special">...</phrase> <phrase role="identifier">args</phrase><phrase role="special">);</phrase>
<phrase role="keyword">template</phrase><phrase role="special">&lt;</phrase> <phrase role="keyword">typename</phrase> <link linkend="stack_allocator_concept"><code><phrase role="identifier">StackAllocator</phrase></code></link><phrase role="special">,</phrase> <phrase role="keyword">class</phrase> <phrase role="identifier">Function</phrase><phrase role="special">,</phrase> <phrase role="keyword">class</phrase> <phrase role="special">...</phrase> <phrase role="identifier">Args</phrase> <phrase role="special">&gt;</phrase>
<phrase role="identifier">future</phrase><phrase role="special">&lt;</phrase>
<phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">result_of_t</phrase><phrase role="special">&lt;</phrase>
<phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">decay_t</phrase><phrase role="special">&lt;</phrase> <phrase role="identifier">Function</phrase> <phrase role="special">&gt;(</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">decay_t</phrase><phrase role="special">&lt;</phrase> <phrase role="identifier">Args</phrase> <phrase role="special">&gt;</phrase> <phrase role="special">...</phrase> <phrase role="special">)</phrase>
<phrase role="special">&gt;</phrase>
<phrase role="special">&gt;</phrase>
<phrase role="identifier">async</phrase><phrase role="special">(</phrase> <link linkend="class_launch"><code><phrase role="identifier">launch</phrase></code></link> <phrase role="identifier">policy</phrase><phrase role="special">,</phrase> <ulink url="http://en.cppreference.com/w/cpp/memory/allocator_arg_t"><code><phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">allocator_arg_t</phrase></code></ulink><phrase role="special">,</phrase> <link linkend="stack_allocator_concept"><code><phrase role="identifier">StackAllocator</phrase></code></link> <phrase role="identifier">salloc</phrase><phrase role="special">,</phrase>
<phrase role="identifier">Function</phrase> <phrase role="special">&amp;&amp;</phrase> <phrase role="identifier">fn</phrase><phrase role="special">,</phrase> <phrase role="identifier">Args</phrase> <phrase role="special">&amp;&amp;</phrase> <phrase role="special">...</phrase> <phrase role="identifier">args</phrase><phrase role="special">);</phrase>
<phrase role="keyword">template</phrase><phrase role="special">&lt;</phrase> <phrase role="keyword">typename</phrase> <link linkend="stack_allocator_concept"><code><phrase role="identifier">StackAllocator</phrase></code></link><phrase role="special">,</phrase> <phrase role="keyword">typename</phrase> <phrase role="identifier">Allocator</phrase><phrase role="special">,</phrase> <phrase role="keyword">class</phrase> <phrase role="identifier">Function</phrase><phrase role="special">,</phrase> <phrase role="keyword">class</phrase> <phrase role="special">...</phrase> <phrase role="identifier">Args</phrase> <phrase role="special">&gt;</phrase>
<phrase role="identifier">future</phrase><phrase role="special">&lt;</phrase>
<phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">result_of_t</phrase><phrase role="special">&lt;</phrase>
<phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">decay_t</phrase><phrase role="special">&lt;</phrase> <phrase role="identifier">Function</phrase> <phrase role="special">&gt;(</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">decay_t</phrase><phrase role="special">&lt;</phrase> <phrase role="identifier">Args</phrase> <phrase role="special">&gt;</phrase> <phrase role="special">...</phrase> <phrase role="special">)</phrase>
<phrase role="special">&gt;</phrase>
<phrase role="special">&gt;</phrase>
<phrase role="identifier">async</phrase><phrase role="special">(</phrase> <link linkend="class_launch"><code><phrase role="identifier">launch</phrase></code></link> <phrase role="identifier">policy</phrase><phrase role="special">,</phrase> <ulink url="http://en.cppreference.com/w/cpp/memory/allocator_arg_t"><code><phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">allocator_arg_t</phrase></code></ulink><phrase role="special">,</phrase> <link linkend="stack_allocator_concept"><code><phrase role="identifier">StackAllocator</phrase></code></link> <phrase role="identifier">salloc</phrase><phrase role="special">,</phrase>
<phrase role="identifier">Allocator</phrase> <phrase role="identifier">alloc</phrase><phrase role="special">,</phrase> <phrase role="identifier">Function</phrase> <phrase role="special">&amp;&amp;</phrase> <phrase role="identifier">fn</phrase><phrase role="special">,</phrase> <phrase role="identifier">Args</phrase> <phrase role="special">&amp;&amp;</phrase> <phrase role="special">...</phrase> <phrase role="identifier">args</phrase><phrase role="special">);</phrase>
<phrase role="special">}}</phrase>
</programlisting>
<variablelist>
<title></title>
<varlistentry>
<term>Effects:</term>
<listitem>
<para>
Executes <code><phrase role="identifier">fn</phrase></code> in a
<link linkend="class_fiber"><code>fiber</code></link> and returns an associated <link linkend="class_future"><code>future&lt;&gt;</code></link>.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>Result:</term>
<listitem>
<para>
<programlisting><phrase role="identifier">future</phrase><phrase role="special">&lt;</phrase>
<phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">result_of_t</phrase><phrase role="special">&lt;</phrase>
<phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">decay_t</phrase><phrase role="special">&lt;</phrase> <phrase role="identifier">Function</phrase> <phrase role="special">&gt;(</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">decay_t</phrase><phrase role="special">&lt;</phrase> <phrase role="identifier">Args</phrase> <phrase role="special">&gt;</phrase> <phrase role="special">...</phrase> <phrase role="special">)</phrase>
<phrase role="special">&gt;</phrase>
<phrase role="special">&gt;</phrase></programlisting>
representing the <link linkend="shared_state">shared state</link>
associated with the asynchronous execution of <code><phrase role="identifier">fn</phrase></code>.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>Throws:</term>
<listitem>
<para>
<code><phrase role="identifier">fiber_error</phrase></code> or <code><phrase
role="identifier">future_error</phrase></code> if an error occurs.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>Notes:</term>
<listitem>
<para>
The overloads accepting <ulink url="http://en.cppreference.com/w/cpp/memory/allocator_arg_t"><code><phrase
role="identifier">std</phrase><phrase role="special">::</phrase><phrase
role="identifier">allocator_arg_t</phrase></code></ulink> use the
passed <link linkend="stack_allocator_concept"><code><phrase role="identifier">StackAllocator</phrase></code></link>
when constructing the launched <code><phrase role="identifier">fiber</phrase></code>.
The overloads accepting <link linkend="class_launch"><code>launch</code></link> use the passed <code><phrase
role="identifier">launch</phrase></code> when constructing the launched
<code><phrase role="identifier">fiber</phrase></code>. The default
<code><phrase role="identifier">launch</phrase></code> is <code><phrase
role="identifier">post</phrase></code>, as for the <code><phrase
role="identifier">fiber</phrase></code> constructor.
</para>
</listitem>
</varlistentry>
</variablelist>
<note>
<para>
Deferred futures are not supported.
</para>
</note>
</section>
<section id="fiber.synchronization.futures.promise">
<title><anchor id="class_promise"/><link linkend="fiber.synchronization.futures.promise">Template
<code><phrase role="identifier">promise</phrase><phrase role="special">&lt;&gt;</phrase></code></link></title>
<para>
A <link linkend="class_promise"><code>promise&lt;&gt;</code></link> provides a mechanism to store a value (or
exception) that can later be retrieved from the corresponding <link linkend="class_future"><code>future&lt;&gt;</code></link> object.
<code><phrase role="identifier">promise</phrase><phrase role="special">&lt;&gt;</phrase></code>
and <code><phrase role="identifier">future</phrase><phrase role="special">&lt;&gt;</phrase></code>
communicate via their underlying <link linkend="shared_state">shared state</link>.
</para>
<programlisting><phrase role="preprocessor">#include</phrase> <phrase role="special">&lt;</phrase><phrase role="identifier">boost</phrase><phrase role="special">/</phrase><phrase role="identifier">fiber</phrase><phrase role="special">/</phrase><phrase role="identifier">future</phrase><phrase role="special">/</phrase><phrase role="identifier">promise</phrase><phrase role="special">.</phrase><phrase role="identifier">hpp</phrase><phrase role="special">&gt;</phrase>
<phrase role="keyword">namespace</phrase> <phrase role="identifier">boost</phrase> <phrase role="special">{</phrase>
<phrase role="keyword">namespace</phrase> <phrase role="identifier">fibers</phrase> <phrase role="special">{</phrase>
<phrase role="keyword">template</phrase><phrase role="special">&lt;</phrase> <phrase role="keyword">typename</phrase> <phrase role="identifier">R</phrase> <phrase role="special">&gt;</phrase>
<phrase role="keyword">class</phrase> <phrase role="identifier">promise</phrase> <phrase role="special">{</phrase>
<phrase role="keyword">public</phrase><phrase role="special">:</phrase>
<phrase role="identifier">promise</phrase><phrase role="special">();</phrase>
<phrase role="keyword">template</phrase><phrase role="special">&lt;</phrase> <phrase role="keyword">typename</phrase> <ulink url="http://en.cppreference.com/w/cpp/concept/Allocator"><code><phrase role="identifier">Allocator</phrase></code></ulink> <phrase role="special">&gt;</phrase>
<phrase role="identifier">promise</phrase><phrase role="special">(</phrase> <ulink url="http://en.cppreference.com/w/cpp/memory/allocator_arg_t"><code><phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">allocator_arg_t</phrase></code></ulink><phrase role="special">,</phrase> <phrase role="identifier">Allocator</phrase><phrase role="special">);</phrase>
<phrase role="identifier">promise</phrase><phrase role="special">(</phrase> <phrase role="identifier">promise</phrase> <phrase role="special">&amp;&amp;)</phrase> <phrase role="keyword">noexcept</phrase><phrase role="special">;</phrase>
<phrase role="identifier">promise</phrase> <phrase role="special">&amp;</phrase> <phrase role="keyword">operator</phrase><phrase role="special">=(</phrase> <phrase role="identifier">promise</phrase> <phrase role="special">&amp;&amp;)</phrase> <phrase role="keyword">noexcept</phrase><phrase role="special">;</phrase>
<phrase role="identifier">promise</phrase><phrase role="special">(</phrase> <phrase role="identifier">promise</phrase> <phrase role="keyword">const</phrase><phrase role="special">&amp;)</phrase> <phrase role="special">=</phrase> <phrase role="keyword">delete</phrase><phrase role="special">;</phrase>
<phrase role="identifier">promise</phrase> <phrase role="special">&amp;</phrase> <phrase role="keyword">operator</phrase><phrase role="special">=(</phrase> <phrase role="identifier">promise</phrase> <phrase role="keyword">const</phrase><phrase role="special">&amp;)</phrase> <phrase role="special">=</phrase> <phrase role="keyword">delete</phrase><phrase role="special">;</phrase>
<phrase role="special">~</phrase><phrase role="identifier">promise</phrase><phrase role="special">();</phrase>
<phrase role="keyword">void</phrase> <phrase role="identifier">swap</phrase><phrase role="special">(</phrase> <phrase role="identifier">promise</phrase> <phrase role="special">&amp;)</phrase> <phrase role="keyword">noexcept</phrase><phrase role="special">;</phrase>
<phrase role="identifier">future</phrase><phrase role="special">&lt;</phrase> <phrase role="identifier">R</phrase> <phrase role="special">&gt;</phrase> <phrase role="identifier">get_future</phrase><phrase role="special">();</phrase>
<phrase role="keyword">void</phrase> <phrase role="identifier">set_value</phrase><phrase role="special">(</phrase> <phrase role="identifier">R</phrase> <phrase role="keyword">const</phrase><phrase role="special">&amp;);</phrase> <phrase role="comment">// member only of generic promise template</phrase>
<phrase role="keyword">void</phrase> <phrase role="identifier">set_value</phrase><phrase role="special">(</phrase> <phrase role="identifier">R</phrase> <phrase role="special">&amp;&amp;);</phrase> <phrase role="comment">// member only of generic promise template</phrase>
<phrase role="keyword">void</phrase> <phrase role="identifier">set_value</phrase><phrase role="special">(</phrase> <phrase role="identifier">R</phrase> <phrase role="special">&amp;);</phrase> <phrase role="comment">// member only of promise&lt; R &amp; &gt; template</phrase>
<phrase role="keyword">void</phrase> <phrase role="identifier">set_value</phrase><phrase role="special">();</phrase> <phrase role="comment">// member only of promise&lt; void &gt; template</phrase>
<phrase role="keyword">void</phrase> <phrase role="identifier">set_exception</phrase><phrase role="special">(</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">exception_ptr</phrase> <phrase role="identifier">p</phrase><phrase role="special">);</phrase>
<phrase role="special">};</phrase>
<phrase role="keyword">template</phrase><phrase role="special">&lt;</phrase> <phrase role="keyword">typename</phrase> <phrase role="identifier">R</phrase> <phrase role="special">&gt;</phrase>
<phrase role="keyword">void</phrase> <phrase role="identifier">swap</phrase><phrase role="special">(</phrase> <phrase role="identifier">promise</phrase><phrase role="special">&lt;</phrase> <phrase role="identifier">R</phrase> <phrase role="special">&gt;</phrase> <phrase role="special">&amp;,</phrase> <phrase role="identifier">promise</phrase><phrase role="special">&lt;</phrase> <phrase role="identifier">R</phrase> <phrase role="special">&gt;</phrase> <phrase role="special">&amp;)</phrase> <phrase role="keyword">noexcept</phrase><phrase role="special">;</phrase>
<phrase role="special">}</phrase>
</programlisting>
<bridgehead renderas="sect5" id="fiber.synchronization.futures.promise.h0">
<phrase id="fiber.synchronization.futures.promise.default_constructor"/><link
linkend="fiber.synchronization.futures.promise.default_constructor">Default
constructor</link>
</bridgehead>
<programlisting><phrase role="identifier">promise</phrase><phrase role="special">();</phrase>
</programlisting>
<variablelist>
<title></title>
<varlistentry>
<term>Effects:</term>
<listitem>
<para>
Creates a promise with an empty <link linkend="shared_state">shared
state</link>.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>Throws:</term>
<listitem>
<para>
Exceptions caused by memory allocation.
</para>
</listitem>
</varlistentry>
</variablelist>
<bridgehead renderas="sect5" id="fiber.synchronization.futures.promise.h1">
<phrase id="fiber.synchronization.futures.promise.constructor"/><link linkend="fiber.synchronization.futures.promise.constructor">Constructor</link>
</bridgehead>
<programlisting><phrase role="keyword">template</phrase><phrase role="special">&lt;</phrase> <phrase role="keyword">typename</phrase> <ulink url="http://en.cppreference.com/w/cpp/concept/Allocator"><code><phrase role="identifier">Allocator</phrase></code></ulink> <phrase role="special">&gt;</phrase>
<phrase role="identifier">promise</phrase><phrase role="special">(</phrase> <ulink url="http://en.cppreference.com/w/cpp/memory/allocator_arg_t"><code><phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">allocator_arg_t</phrase></code></ulink><phrase role="special">,</phrase> <phrase role="identifier">Allocator</phrase> <phrase role="identifier">alloc</phrase><phrase role="special">);</phrase>
</programlisting>
<variablelist>
<title></title>
<varlistentry>
<term>Effects:</term>
<listitem>
<para>
Creates a promise with an empty <link linkend="shared_state">shared
state</link> by using <code><phrase role="identifier">alloc</phrase></code>.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>Throws:</term>
<listitem>
<para>
Exceptions caused by memory allocation.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>See also:</term>
<listitem>
<para>
<ulink url="http://en.cppreference.com/w/cpp/memory/allocator_arg_t"><code><phrase
role="identifier">std</phrase><phrase role="special">::</phrase><phrase
role="identifier">allocator_arg_t</phrase></code></ulink>
</para>
</listitem>
</varlistentry>
</variablelist>
<bridgehead renderas="sect5" id="fiber.synchronization.futures.promise.h2">
<phrase id="fiber.synchronization.futures.promise.move_constructor"/><link
linkend="fiber.synchronization.futures.promise.move_constructor">Move constructor</link>
</bridgehead>
<programlisting><phrase role="identifier">promise</phrase><phrase role="special">(</phrase> <phrase role="identifier">promise</phrase> <phrase role="special">&amp;&amp;</phrase> <phrase role="identifier">other</phrase><phrase role="special">)</phrase> <phrase role="keyword">noexcept</phrase><phrase role="special">;</phrase>
</programlisting>
<variablelist>
<title></title>
<varlistentry>
<term>Effects:</term>
<listitem>
<para>
Creates a promise by moving the <link linkend="shared_state">shared
state</link> from <code><phrase role="identifier">other</phrase></code>.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>Postcondition:</term>
<listitem>
<para>
<code><phrase role="identifier">other</phrase></code> contains no
valid shared state.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>Throws:</term>
<listitem>
<para>
Nothing.
</para>
</listitem>
</varlistentry>
</variablelist>
<bridgehead renderas="sect5" id="fiber.synchronization.futures.promise.h3">
<phrase id="fiber.synchronization.futures.promise.destructor"/><link linkend="fiber.synchronization.futures.promise.destructor">Destructor</link>
</bridgehead>
<programlisting><phrase role="special">~</phrase><phrase role="identifier">promise</phrase><phrase role="special">();</phrase>
</programlisting>
<variablelist>
<title></title>
<varlistentry>
<term>Effects:</term>
<listitem>
<para>
Destroys <code><phrase role="special">*</phrase><phrase role="keyword">this</phrase></code>
and abandons the <link linkend="shared_state">shared state</link>
if shared state is ready; otherwise stores <code><phrase role="identifier">future_error</phrase></code>
with error condition <code><phrase role="identifier">future_errc</phrase><phrase
role="special">::</phrase><phrase role="identifier">broken_promise</phrase></code>
as if by <link linkend="promise_set_exception"><code>promise::set_exception()</code></link>: the shared
state is set ready.
</para>
</listitem>
</varlistentry>
</variablelist>
<para>
<bridgehead renderas="sect4" id="promise_operator_assign_bridgehead">
<phrase id="promise_operator_assign"/>
<link linkend="promise_operator_assign">Member
function <code>operator=</code>()</link>
</bridgehead>
</para>
<programlisting><phrase role="identifier">promise</phrase> <phrase role="special">&amp;</phrase> <phrase role="keyword">operator</phrase><phrase role="special">=(</phrase> <phrase role="identifier">promise</phrase> <phrase role="special">&amp;&amp;</phrase> <phrase role="identifier">other</phrase><phrase role="special">)</phrase> <phrase role="keyword">noexcept</phrase><phrase role="special">;</phrase>
</programlisting>
<variablelist>
<title></title>
<varlistentry>
<term>Effects:</term>
<listitem>
<para>
Transfers the ownership of <link linkend="shared_state">shared state</link>
to <code><phrase role="special">*</phrase><phrase role="keyword">this</phrase></code>.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>Postcondition:</term>
<listitem>
<para>
<code><phrase role="identifier">other</phrase></code> contains no
valid shared state.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>Throws:</term>
<listitem>
<para>
Nothing.
</para>
</listitem>
</varlistentry>
</variablelist>
<para>
<bridgehead renderas="sect4" id="promise_swap_bridgehead">
<phrase id="promise_swap"/>
<link linkend="promise_swap">Member function <code>swap</code>()</link>
</bridgehead>
</para>
<programlisting><phrase role="keyword">void</phrase> <phrase role="identifier">swap</phrase><phrase role="special">(</phrase> <phrase role="identifier">promise</phrase> <phrase role="special">&amp;</phrase> <phrase role="identifier">other</phrase><phrase role="special">)</phrase> <phrase role="keyword">noexcept</phrase><phrase role="special">;</phrase>
</programlisting>
<variablelist>
<title></title>
<varlistentry>
<term>Effects:</term>
<listitem>
<para>
Swaps the <link linkend="shared_state">shared state</link> between
other and <code><phrase role="special">*</phrase><phrase role="keyword">this</phrase></code>.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>Throws:</term>
<listitem>
<para>
Nothing.
</para>
</listitem>
</varlistentry>
</variablelist>
<para>
<bridgehead renderas="sect4" id="promise_get_future_bridgehead">
<phrase id="promise_get_future"/>
<link linkend="promise_get_future">Member
function <code>get_future</code>()</link>
</bridgehead>
</para>
<programlisting><phrase role="identifier">future</phrase><phrase role="special">&lt;</phrase> <phrase role="identifier">R</phrase> <phrase role="special">&gt;</phrase> <phrase role="identifier">get_future</phrase><phrase role="special">();</phrase>
</programlisting>
<variablelist>
<title></title>
<varlistentry>
<term>Returns:</term>
<listitem>
<para>
A <link linkend="class_future"><code>future&lt;&gt;</code></link> with the same <link linkend="shared_state">shared
state</link>.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>Throws:</term>
<listitem>
<para>
<code><phrase role="identifier">future_error</phrase></code> with
<code><phrase role="identifier">future_errc</phrase><phrase role="special">::</phrase><phrase
role="identifier">future_already_retrieved</phrase></code> or <code><phrase
role="identifier">future_errc</phrase><phrase role="special">::</phrase><phrase
role="identifier">no_state</phrase></code>.
</para>
</listitem>
</varlistentry>
</variablelist>
<para>
<bridgehead renderas="sect4" id="promise_set_value_bridgehead">
<phrase id="promise_set_value"/>
<link linkend="promise_set_value">Member function
<code>set_value</code>()</link>
</bridgehead>
</para>
<programlisting><phrase role="keyword">void</phrase> <phrase role="identifier">set_value</phrase><phrase role="special">(</phrase> <phrase role="identifier">R</phrase> <phrase role="keyword">const</phrase><phrase role="special">&amp;</phrase> <phrase role="identifier">value</phrase><phrase role="special">);</phrase> <phrase role="comment">// member only of generic promise template</phrase>
<phrase role="keyword">void</phrase> <phrase role="identifier">set_value</phrase><phrase role="special">(</phrase> <phrase role="identifier">R</phrase> <phrase role="special">&amp;&amp;</phrase> <phrase role="identifier">value</phrase><phrase role="special">);</phrase> <phrase role="comment">// member only of generic promise template</phrase>
<phrase role="keyword">void</phrase> <phrase role="identifier">set_value</phrase><phrase role="special">(</phrase> <phrase role="identifier">R</phrase> <phrase role="special">&amp;</phrase> <phrase role="identifier">value</phrase><phrase role="special">);</phrase> <phrase role="comment">// member only of promise&lt; R &amp; &gt; template</phrase>
<phrase role="keyword">void</phrase> <phrase role="identifier">set_value</phrase><phrase role="special">();</phrase> <phrase role="comment">// member only of promise&lt; void &gt; template</phrase>
</programlisting>
<variablelist>
<title></title>
<varlistentry>
<term>Effects:</term>
<listitem>
<para>
Store the result in the <link linkend="shared_state">shared state</link>
and marks the state as ready.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>Throws:</term>
<listitem>
<para>
<code><phrase role="identifier">future_error</phrase></code> with
<code><phrase role="identifier">future_errc</phrase><phrase role="special">::</phrase><phrase
role="identifier">future_already_satisfied</phrase></code> or <code><phrase
role="identifier">future_errc</phrase><phrase role="special">::</phrase><phrase
role="identifier">no_state</phrase></code>.
</para>
</listitem>
</varlistentry>
</variablelist>
<para>
<bridgehead renderas="sect4" id="promise_set_exception_bridgehead">
<phrase id="promise_set_exception"/>
<link linkend="promise_set_exception">Member
function <code>set_exception</code>()</link>
</bridgehead>
</para>
<programlisting><phrase role="keyword">void</phrase> <phrase role="identifier">set_exception</phrase><phrase role="special">(</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">exception_ptr</phrase><phrase role="special">);</phrase>
</programlisting>
<variablelist>
<title></title>
<varlistentry>
<term>Effects:</term>
<listitem>
<para>
Store an exception pointer in the <link linkend="shared_state">shared
state</link> and marks the state as ready.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>Throws:</term>
<listitem>
<para>
<code><phrase role="identifier">future_error</phrase></code> with
<code><phrase role="identifier">future_errc</phrase><phrase role="special">::</phrase><phrase
role="identifier">future_already_satisfied</phrase></code> or <code><phrase
role="identifier">future_errc</phrase><phrase role="special">::</phrase><phrase
role="identifier">no_state</phrase></code>.
</para>
</listitem>
</varlistentry>
</variablelist>
<para>
<bridgehead renderas="sect4" id="swap_for_promise_bridgehead">
<phrase id="swap_for_promise"/>
<link linkend="swap_for_promise">Non-member function
<code>swap()</code></link>
</bridgehead>
</para>
<programlisting><phrase role="keyword">template</phrase><phrase role="special">&lt;</phrase> <phrase role="keyword">typename</phrase> <phrase role="identifier">R</phrase> <phrase role="special">&gt;</phrase>
<phrase role="keyword">void</phrase> <phrase role="identifier">swap</phrase><phrase role="special">(</phrase> <phrase role="identifier">promise</phrase><phrase role="special">&lt;</phrase> <phrase role="identifier">R</phrase> <phrase role="special">&gt;</phrase> <phrase role="special">&amp;</phrase> <phrase role="identifier">l</phrase><phrase role="special">,</phrase> <phrase role="identifier">promise</phrase><phrase role="special">&lt;</phrase> <phrase role="identifier">R</phrase> <phrase role="special">&gt;</phrase> <phrase role="special">&amp;</phrase> <phrase role="identifier">r</phrase><phrase role="special">)</phrase> <phrase role="keyword">noexcept</phrase><phrase role="special">;</phrase>
</programlisting>
<variablelist>
<title></title>
<varlistentry>
<term>Effects:</term>
<listitem>
<para>
Same as <code><phrase role="identifier">l</phrase><phrase role="special">.</phrase><phrase
role="identifier">swap</phrase><phrase role="special">(</phrase>
<phrase role="identifier">r</phrase><phrase role="special">)</phrase></code>.
</para>
</listitem>
</varlistentry>
</variablelist>
</section>
<section id="fiber.synchronization.futures.packaged_task">
<title><anchor id="class_packaged_task"/><link linkend="fiber.synchronization.futures.packaged_task">Template
<code><phrase role="identifier">packaged_task</phrase><phrase role="special">&lt;&gt;</phrase></code></link></title>
<para>
A <link linkend="class_packaged_task"><code>packaged_task&lt;&gt;</code></link> wraps a callable target that
returns a value so that the return value can be computed asynchronously.
</para>
<para>
Conventional usage of <code><phrase role="identifier">packaged_task</phrase><phrase
role="special">&lt;&gt;</phrase></code> is like this:
</para>
<orderedlist>
<listitem>
<simpara>
Instantiate <code><phrase role="identifier">packaged_task</phrase><phrase
role="special">&lt;&gt;</phrase></code> with template arguments matching
the signature of the callable. Pass the callable to the <link linkend="packaged_task_packaged_task">constructor</link>.
</simpara>
</listitem>
<listitem>
<simpara>
Call <link linkend="packaged_task_get_future"><code>packaged_task::get_future()</code></link> and capture
the returned <link linkend="class_future"><code>future&lt;&gt;</code></link> instance.
</simpara>
</listitem>
<listitem>
<simpara>
Launch a <link linkend="class_fiber"><code>fiber</code></link> to run the new <code><phrase role="identifier">packaged_task</phrase><phrase
role="special">&lt;&gt;</phrase></code>, passing any arguments required
by the original callable.
</simpara>
</listitem>
<listitem>
<simpara>
Call <link linkend="fiber_detach"><code>fiber::detach()</code></link> on the newly-launched <code><phrase
role="identifier">fiber</phrase></code>.
</simpara>
</listitem>
<listitem>
<simpara>
At some later point, retrieve the result from the <code><phrase role="identifier">future</phrase><phrase
role="special">&lt;&gt;</phrase></code>.
</simpara>
</listitem>
</orderedlist>
<para>
This is, in fact, pretty much what <link linkend="fibers_async"><code>fibers::async()</code></link>
encapsulates.
</para>
<programlisting><phrase role="preprocessor">#include</phrase> <phrase role="special">&lt;</phrase><phrase role="identifier">boost</phrase><phrase role="special">/</phrase><phrase role="identifier">fiber</phrase><phrase role="special">/</phrase><phrase role="identifier">future</phrase><phrase role="special">/</phrase><phrase role="identifier">packaged_task</phrase><phrase role="special">.</phrase><phrase role="identifier">hpp</phrase><phrase role="special">&gt;</phrase>
<phrase role="keyword">namespace</phrase> <phrase role="identifier">boost</phrase> <phrase role="special">{</phrase>
<phrase role="keyword">namespace</phrase> <phrase role="identifier">fibers</phrase> <phrase role="special">{</phrase>
<phrase role="keyword">template</phrase><phrase role="special">&lt;</phrase> <phrase role="keyword">class</phrase> <phrase role="identifier">R</phrase><phrase role="special">,</phrase> <phrase role="keyword">typename</phrase> <phrase role="special">...</phrase> <phrase role="identifier">Args</phrase> <phrase role="special">&gt;</phrase>
<phrase role="keyword">class</phrase> <phrase role="identifier">packaged_task</phrase><phrase role="special">&lt;</phrase> <phrase role="identifier">R</phrase><phrase role="special">(</phrase> <phrase role="identifier">Args</phrase> <phrase role="special">...</phrase> <phrase role="special">)</phrase> <phrase role="special">&gt;</phrase> <phrase role="special">{</phrase>
<phrase role="keyword">public</phrase><phrase role="special">:</phrase>
<phrase role="identifier">packaged_task</phrase><phrase role="special">()</phrase> <phrase role="keyword">noexcept</phrase><phrase role="special">;</phrase>
<phrase role="keyword">template</phrase><phrase role="special">&lt;</phrase> <phrase role="keyword">typename</phrase> <phrase role="identifier">Fn</phrase> <phrase role="special">&gt;</phrase>
<phrase role="keyword">explicit</phrase> <phrase role="identifier">packaged_task</phrase><phrase role="special">(</phrase> <phrase role="identifier">Fn</phrase> <phrase role="special">&amp;&amp;);</phrase>
<phrase role="keyword">template</phrase><phrase role="special">&lt;</phrase> <phrase role="keyword">typename</phrase> <phrase role="identifier">Fn</phrase><phrase role="special">,</phrase> <phrase role="keyword">typename</phrase> <ulink url="http://en.cppreference.com/w/cpp/concept/Allocator"><code><phrase role="identifier">Allocator</phrase></code></ulink> <phrase role="special">&gt;</phrase>
<phrase role="identifier">packaged_task</phrase><phrase role="special">(</phrase> <ulink url="http://en.cppreference.com/w/cpp/memory/allocator_arg_t"><code><phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">allocator_arg_t</phrase></code></ulink><phrase role="special">,</phrase> <phrase role="identifier">Allocator</phrase> <phrase role="keyword">const</phrase><phrase role="special">&amp;,</phrase> <phrase role="identifier">Fn</phrase> <phrase role="special">&amp;&amp;);</phrase>
<phrase role="identifier">packaged_task</phrase><phrase role="special">(</phrase> <phrase role="identifier">packaged_task</phrase> <phrase role="special">&amp;&amp;)</phrase> <phrase role="keyword">noexcept</phrase><phrase role="special">;</phrase>
<phrase role="identifier">packaged_task</phrase> <phrase role="special">&amp;</phrase> <phrase role="keyword">operator</phrase><phrase role="special">=(</phrase> <phrase role="identifier">packaged_task</phrase> <phrase role="special">&amp;&amp;)</phrase> <phrase role="keyword">noexcept</phrase><phrase role="special">;</phrase>
<phrase role="identifier">packaged_task</phrase><phrase role="special">(</phrase> <phrase role="identifier">packaged_task</phrase> <phrase role="keyword">const</phrase><phrase role="special">&amp;)</phrase> <phrase role="special">=</phrase> <phrase role="keyword">delete</phrase><phrase role="special">;</phrase>
<phrase role="identifier">packaged_task</phrase> <phrase role="special">&amp;</phrase> <phrase role="keyword">operator</phrase><phrase role="special">=(</phrase> <phrase role="identifier">packaged_task</phrase> <phrase role="keyword">const</phrase><phrase role="special">&amp;)</phrase> <phrase role="special">=</phrase> <phrase role="keyword">delete</phrase><phrase role="special">;</phrase>
<phrase role="special">~</phrase><phrase role="identifier">packaged_task</phrase><phrase role="special">();</phrase>
<phrase role="keyword">void</phrase> <phrase role="identifier">swap</phrase><phrase role="special">(</phrase> <phrase role="identifier">packaged_task</phrase> <phrase role="special">&amp;)</phrase> <phrase role="keyword">noexcept</phrase><phrase role="special">;</phrase>
<phrase role="keyword">bool</phrase> <phrase role="identifier">valid</phrase><phrase role="special">()</phrase> <phrase role="keyword">const</phrase> <phrase role="keyword">noexcept</phrase><phrase role="special">;</phrase>
<phrase role="identifier">future</phrase><phrase role="special">&lt;</phrase> <phrase role="identifier">R</phrase> <phrase role="special">&gt;</phrase> <phrase role="identifier">get_future</phrase><phrase role="special">();</phrase>
<phrase role="keyword">void</phrase> <phrase role="keyword">operator</phrase><phrase role="special">()(</phrase> <phrase role="identifier">Args</phrase> <phrase role="special">...);</phrase>
<phrase role="keyword">void</phrase> <phrase role="identifier">reset</phrase><phrase role="special">();</phrase>
<phrase role="special">};</phrase>
<phrase role="keyword">template</phrase><phrase role="special">&lt;</phrase> <phrase role="keyword">typename</phrase> <phrase role="identifier">Signature</phrase> <phrase role="special">&gt;</phrase>
<phrase role="keyword">void</phrase> <phrase role="identifier">swap</phrase><phrase role="special">(</phrase> <phrase role="identifier">packaged_task</phrase><phrase role="special">&lt;</phrase> <phrase role="identifier">Signature</phrase> <phrase role="special">&gt;</phrase> <phrase role="special">&amp;,</phrase> <phrase role="identifier">packaged_task</phrase><phrase role="special">&lt;</phrase> <phrase role="identifier">Signature</phrase> <phrase role="special">&gt;</phrase> <phrase role="special">&amp;)</phrase> <phrase role="keyword">noexcept</phrase><phrase role="special">;</phrase>
<phrase role="special">}}</phrase>
</programlisting>
<bridgehead renderas="sect5" id="fiber.synchronization.futures.packaged_task.h0">
<phrase id="fiber.synchronization.futures.packaged_task.default_constructor__code__phrase_role__identifier__packaged_task__phrase__phrase_role__special______phrase___code_"/><link
linkend="fiber.synchronization.futures.packaged_task.default_constructor__code__phrase_role__identifier__packaged_task__phrase__phrase_role__special______phrase___code_">Default
constructor <code><phrase role="identifier">packaged_task</phrase><phrase
role="special">()</phrase></code></link>
</bridgehead>
<programlisting><phrase role="identifier">packaged_task</phrase><phrase role="special">()</phrase> <phrase role="keyword">noexcept</phrase><phrase role="special">;</phrase>
</programlisting>
<variablelist>
<title></title>
<varlistentry>
<term>Effects:</term>
<listitem>
<para>
Constructs an object of class <code><phrase role="identifier">packaged_task</phrase></code>
with no <link linkend="shared_state">shared state</link>.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>Throws:</term>
<listitem>
<para>
Nothing.
</para>
</listitem>
</varlistentry>
</variablelist>
<anchor id="packaged_task_packaged_task"/>
<bridgehead renderas="sect5" id="fiber.synchronization.futures.packaged_task.h1">
<phrase id="fiber.synchronization.futures.packaged_task.templated_constructor__code__phrase_role__identifier__packaged_task__phrase__phrase_role__special______phrase___code_"/><link
linkend="fiber.synchronization.futures.packaged_task.templated_constructor__code__phrase_role__identifier__packaged_task__phrase__phrase_role__special______phrase___code_">Templated
constructor <code><phrase role="identifier">packaged_task</phrase><phrase
role="special">()</phrase></code></link>
</bridgehead>
<programlisting><phrase role="keyword">template</phrase><phrase role="special">&lt;</phrase> <phrase role="keyword">typename</phrase> <phrase role="identifier">Fn</phrase> <phrase role="special">&gt;</phrase>
<phrase role="keyword">explicit</phrase> <phrase role="identifier">packaged_task</phrase><phrase role="special">(</phrase> <phrase role="identifier">Fn</phrase> <phrase role="special">&amp;&amp;</phrase> <phrase role="identifier">fn</phrase><phrase role="special">);</phrase>
<phrase role="keyword">template</phrase><phrase role="special">&lt;</phrase> <phrase role="keyword">typename</phrase> <phrase role="identifier">Fn</phrase><phrase role="special">,</phrase> <phrase role="keyword">typename</phrase> <ulink url="http://en.cppreference.com/w/cpp/concept/Allocator"><code><phrase role="identifier">Allocator</phrase></code></ulink> <phrase role="special">&gt;</phrase>
<phrase role="identifier">packaged_task</phrase><phrase role="special">(</phrase> <ulink url="http://en.cppreference.com/w/cpp/memory/allocator_arg_t"><code><phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">allocator_arg_t</phrase></code></ulink><phrase role="special">,</phrase> <phrase role="identifier">Allocator</phrase> <phrase role="keyword">const</phrase><phrase role="special">&amp;</phrase> <phrase role="identifier">alloc</phrase><phrase role="special">,</phrase> <phrase role="identifier">Fn</phrase> <phrase role="special">&amp;&amp;</phrase> <phrase role="identifier">fn</phrase><phrase role="special">);</phrase>
</programlisting>
<variablelist>
<title></title>
<varlistentry>
<term>Effects:</term>
<listitem>
<para>
Constructs an object of class <code><phrase role="identifier">packaged_task</phrase></code>
with a <link linkend="shared_state">shared state</link> and copies
or moves the callable target <code><phrase role="identifier">fn</phrase></code>
to internal storage.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>Throws:</term>
<listitem>
<para>
Exceptions caused by memory allocation.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>Note:</term>
<listitem>
<para>
The signature of <code><phrase role="identifier">Fn</phrase></code>
should have a return type convertible to <code><phrase role="identifier">R</phrase></code>.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>See also:</term>
<listitem>
<para>
<ulink url="http://en.cppreference.com/w/cpp/memory/allocator_arg_t"><code><phrase
role="identifier">std</phrase><phrase role="special">::</phrase><phrase
role="identifier">allocator_arg_t</phrase></code></ulink>
</para>
</listitem>
</varlistentry>
</variablelist>
<bridgehead renderas="sect5" id="fiber.synchronization.futures.packaged_task.h2">
<phrase id="fiber.synchronization.futures.packaged_task.move_constructor"/><link
linkend="fiber.synchronization.futures.packaged_task.move_constructor">Move
constructor</link>
</bridgehead>
<programlisting><phrase role="identifier">packaged_task</phrase><phrase role="special">(</phrase> <phrase role="identifier">packaged_task</phrase> <phrase role="special">&amp;&amp;</phrase> <phrase role="identifier">other</phrase><phrase role="special">)</phrase> <phrase role="keyword">noexcept</phrase><phrase role="special">;</phrase>
</programlisting>
<variablelist>
<title></title>
<varlistentry>
<term>Effects:</term>
<listitem>
<para>
Creates a packaged_task by moving the <link linkend="shared_state">shared
state</link> from <code><phrase role="identifier">other</phrase></code>.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>Postcondition:</term>
<listitem>
<para>
<code><phrase role="identifier">other</phrase></code> contains no
valid shared state.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>Throws:</term>
<listitem>
<para>
Nothing.
</para>
</listitem>
</varlistentry>
</variablelist>
<bridgehead renderas="sect5" id="fiber.synchronization.futures.packaged_task.h3">
<phrase id="fiber.synchronization.futures.packaged_task.destructor"/><link
linkend="fiber.synchronization.futures.packaged_task.destructor">Destructor</link>
</bridgehead>
<programlisting><phrase role="special">~</phrase><phrase role="identifier">packaged_task</phrase><phrase role="special">();</phrase>
</programlisting>
<variablelist>
<title></title>
<varlistentry>
<term>Effects:</term>
<listitem>
<para>
Destroys <code><phrase role="special">*</phrase><phrase role="keyword">this</phrase></code>
and abandons the <link linkend="shared_state">shared state</link>
if shared state is ready; otherwise stores <code><phrase role="identifier">future_error</phrase></code>
with error condition <code><phrase role="identifier">future_errc</phrase><phrase
role="special">::</phrase><phrase role="identifier">broken_promise</phrase></code>
as if by <link linkend="promise_set_exception"><code>promise::set_exception()</code></link>: the shared
state is set ready.
</para>
</listitem>
</varlistentry>
</variablelist>
<para>
<bridgehead renderas="sect4" id="packaged_task_operator_assign_bridgehead">
<phrase id="packaged_task_operator_assign"/>
<link linkend="packaged_task_operator_assign">Member
function <code>operator=</code>()</link>
</bridgehead>
</para>
<programlisting><phrase role="identifier">packaged_task</phrase> <phrase role="special">&amp;</phrase> <phrase role="keyword">operator</phrase><phrase role="special">=(</phrase> <phrase role="identifier">packaged_task</phrase> <phrase role="special">&amp;&amp;</phrase> <phrase role="identifier">other</phrase><phrase role="special">)</phrase> <phrase role="keyword">noexcept</phrase><phrase role="special">;</phrase>
</programlisting>
<variablelist>
<title></title>
<varlistentry>
<term>Effects:</term>
<listitem>
<para>
Transfers the ownership of <link linkend="shared_state">shared state</link>
to <code><phrase role="special">*</phrase><phrase role="keyword">this</phrase></code>.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>Postcondition:</term>
<listitem>
<para>
<code><phrase role="identifier">other</phrase></code> contains no
valid shared state.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>Throws:</term>
<listitem>
<para>
Nothing.
</para>
</listitem>
</varlistentry>
</variablelist>
<para>
<bridgehead renderas="sect4" id="packaged_task_swap_bridgehead">
<phrase id="packaged_task_swap"/>
<link linkend="packaged_task_swap">Member
function <code>swap</code>()</link>
</bridgehead>
</para>
<programlisting><phrase role="keyword">void</phrase> <phrase role="identifier">swap</phrase><phrase role="special">(</phrase> <phrase role="identifier">packaged_task</phrase> <phrase role="special">&amp;</phrase> <phrase role="identifier">other</phrase><phrase role="special">)</phrase> <phrase role="keyword">noexcept</phrase><phrase role="special">;</phrase>
</programlisting>
<variablelist>
<title></title>
<varlistentry>
<term>Effects:</term>
<listitem>
<para>
Swaps the <link linkend="shared_state">shared state</link> between
other and <code><phrase role="special">*</phrase><phrase role="keyword">this</phrase></code>.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>Throws:</term>
<listitem>
<para>
Nothing.
</para>
</listitem>
</varlistentry>
</variablelist>
<para>
<bridgehead renderas="sect4" id="packaged_task_valid_bridgehead">
<phrase id="packaged_task_valid"/>
<link linkend="packaged_task_valid">Member
function <code>valid</code>()</link>
</bridgehead>
</para>
<programlisting><phrase role="keyword">bool</phrase> <phrase role="identifier">valid</phrase><phrase role="special">()</phrase> <phrase role="keyword">const</phrase> <phrase role="keyword">noexcept</phrase><phrase role="special">;</phrase>
</programlisting>
<variablelist>
<title></title>
<varlistentry>
<term>Effects:</term>
<listitem>
<para>
Returns <code><phrase role="keyword">true</phrase></code> if <code><phrase
role="special">*</phrase><phrase role="keyword">this</phrase></code>
contains a <link linkend="shared_state">shared state</link>.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>Throws:</term>
<listitem>
<para>
Nothing.
</para>
</listitem>
</varlistentry>
</variablelist>
<para>
<bridgehead renderas="sect4" id="packaged_task_get_future_bridgehead">
<phrase id="packaged_task_get_future"/>
<link linkend="packaged_task_get_future">Member
function <code>get_future</code>()</link>
</bridgehead>
</para>
<programlisting><phrase role="identifier">future</phrase><phrase role="special">&lt;</phrase> <phrase role="identifier">R</phrase> <phrase role="special">&gt;</phrase> <phrase role="identifier">get_future</phrase><phrase role="special">();</phrase>
</programlisting>
<variablelist>
<title></title>
<varlistentry>
<term>Returns:</term>
<listitem>
<para>
A <link linkend="class_future"><code>future&lt;&gt;</code></link> with the same <link linkend="shared_state">shared
state</link>.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>Throws:</term>
<listitem>
<para>
<code><phrase role="identifier">future_error</phrase></code> with
<code><phrase role="identifier">future_errc</phrase><phrase role="special">::</phrase><phrase
role="identifier">future_already_retrieved</phrase></code> or <code><phrase
role="identifier">future_errc</phrase><phrase role="special">::</phrase><phrase
role="identifier">no_state</phrase></code>.
</para>
</listitem>
</varlistentry>
</variablelist>
<para>
<bridgehead renderas="sect4" id="packaged_task_operator_apply_bridgehead">
<phrase id="packaged_task_operator_apply"/>
<link linkend="packaged_task_operator_apply">Member
function <code>operator()</code>()</link>
</bridgehead>
</para>
<programlisting><phrase role="keyword">void</phrase> <phrase role="keyword">operator</phrase><phrase role="special">()(</phrase> <phrase role="identifier">Args</phrase> <phrase role="special">&amp;&amp;</phrase> <phrase role="special">...</phrase> <phrase role="identifier">args</phrase><phrase role="special">);</phrase>
</programlisting>
<variablelist>
<title></title>
<varlistentry>
<term>Effects:</term>
<listitem>
<para>
Invokes the stored callable target. Any exception thrown by the callable
target <code><phrase role="identifier">fn</phrase></code> is stored
in the <link linkend="shared_state">shared state</link> as if by
<link linkend="promise_set_exception"><code>promise::set_exception()</code></link>. Otherwise, the value
returned by <code><phrase role="identifier">fn</phrase></code> is
stored in the shared state as if by <link linkend="promise_set_value"><code>promise::set_value()</code></link>.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>Throws:</term>
<listitem>
<para>
<code><phrase role="identifier">future_error</phrase></code> with
<code><phrase role="identifier">future_errc</phrase><phrase role="special">::</phrase><phrase
role="identifier">no_state</phrase></code>.
</para>
</listitem>
</varlistentry>
</variablelist>
<para>
<bridgehead renderas="sect4" id="packaged_task_reset_bridgehead">
<phrase id="packaged_task_reset"/>
<link linkend="packaged_task_reset">Member
function <code>reset</code>()</link>
</bridgehead>
</para>
<programlisting><phrase role="keyword">void</phrase> <phrase role="identifier">reset</phrase><phrase role="special">();</phrase>
</programlisting>
<variablelist>
<title></title>
<varlistentry>
<term>Effects:</term>
<listitem>
<para>
Resets the <link linkend="shared_state">shared state</link> and abandons
the result of previous executions. A new shared state is constructed.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>Throws:</term>
<listitem>
<para>
<code><phrase role="identifier">future_error</phrase></code> with
<code><phrase role="identifier">future_errc</phrase><phrase role="special">::</phrase><phrase
role="identifier">no_state</phrase></code>.
</para>
</listitem>
</varlistentry>
</variablelist>
<para>
<bridgehead renderas="sect4" id="swap_for_packaged_task_bridgehead">
<phrase id="swap_for_packaged_task"/>
<link linkend="swap_for_packaged_task">Non-member
function <code>swap()</code></link>
</bridgehead>
</para>
<programlisting><phrase role="keyword">template</phrase><phrase role="special">&lt;</phrase> <phrase role="keyword">typename</phrase> <phrase role="identifier">Signature</phrase> <phrase role="special">&gt;</phrase>
<phrase role="keyword">void</phrase> <phrase role="identifier">swap</phrase><phrase role="special">(</phrase> <phrase role="identifier">packaged_task</phrase><phrase role="special">&lt;</phrase> <phrase role="identifier">Signature</phrase> <phrase role="special">&gt;</phrase> <phrase role="special">&amp;</phrase> <phrase role="identifier">l</phrase><phrase role="special">,</phrase> <phrase role="identifier">packaged_task</phrase><phrase role="special">&lt;</phrase> <phrase role="identifier">Signature</phrase> <phrase role="special">&gt;</phrase> <phrase role="special">&amp;</phrase> <phrase role="identifier">r</phrase><phrase role="special">)</phrase> <phrase role="keyword">noexcept</phrase><phrase role="special">;</phrase>
</programlisting>
<variablelist>
<title></title>
<varlistentry>
<term>Effects:</term>
<listitem>
<para>
Same as <code><phrase role="identifier">l</phrase><phrase role="special">.</phrase><phrase
role="identifier">swap</phrase><phrase role="special">(</phrase>
<phrase role="identifier">r</phrase><phrase role="special">)</phrase></code>.
</para>
</listitem>
</varlistentry>
</variablelist>
</section>
</section>
</section>
<section id="fiber.fls">
<title><link linkend="fiber.fls">Fiber local storage</link></title>
<bridgehead renderas="sect3" id="fiber.fls.h0">
<phrase id="fiber.fls.synopsis"/><link linkend="fiber.fls.synopsis">Synopsis</link>
</bridgehead>
<para>
Fiber local storage allows a separate instance of a given data item for each
fiber.
</para>
<bridgehead renderas="sect3" id="fiber.fls.h1">
<phrase id="fiber.fls.cleanup_at_fiber_exit"/><link linkend="fiber.fls.cleanup_at_fiber_exit">Cleanup
at fiber exit</link>
</bridgehead>
<para>
When a fiber exits, the objects associated with each <link linkend="class_fiber_specific_ptr"><code>fiber_specific_ptr</code></link> instance
are destroyed. By default, the object pointed to by a pointer <code><phrase
role="identifier">p</phrase></code> is destroyed by invoking <code><phrase
role="keyword">delete</phrase> <phrase role="identifier">p</phrase></code>,
but this can be overridden for a specific instance of <link linkend="class_fiber_specific_ptr"><code>fiber_specific_ptr</code></link> by
providing a cleanup routine <code><phrase role="identifier">func</phrase></code>
to the constructor. In this case, the object is destroyed by invoking <code><phrase
role="identifier">func</phrase><phrase role="special">(</phrase><phrase role="identifier">p</phrase><phrase
role="special">)</phrase></code>. The cleanup functions are called in an unspecified
order.
</para>
<para>
<bridgehead renderas="sect4" id="class_fiber_specific_ptr_bridgehead">
<phrase id="class_fiber_specific_ptr"/>
<link linkend="class_fiber_specific_ptr">Class
<code>fiber_specific_ptr</code></link>
</bridgehead>
</para>
<programlisting><phrase role="preprocessor">#include</phrase> <phrase role="special">&lt;</phrase><phrase role="identifier">boost</phrase><phrase role="special">/</phrase><phrase role="identifier">fiber</phrase><phrase role="special">/</phrase><phrase role="identifier">fss</phrase><phrase role="special">.</phrase><phrase role="identifier">hpp</phrase><phrase role="special">&gt;</phrase>
<phrase role="keyword">namespace</phrase> <phrase role="identifier">boost</phrase> <phrase role="special">{</phrase>
<phrase role="keyword">namespace</phrase> <phrase role="identifier">fibers</phrase> <phrase role="special">{</phrase>
<phrase role="keyword">template</phrase><phrase role="special">&lt;</phrase> <phrase role="keyword">typename</phrase> <phrase role="identifier">T</phrase> <phrase role="special">&gt;</phrase>
<phrase role="keyword">class</phrase> <phrase role="identifier">fiber_specific_ptr</phrase> <phrase role="special">{</phrase>
<phrase role="keyword">public</phrase><phrase role="special">:</phrase>
<phrase role="keyword">typedef</phrase> <phrase role="identifier">T</phrase> <phrase role="identifier">element_type</phrase><phrase role="special">;</phrase>
<phrase role="identifier">fiber_specific_ptr</phrase><phrase role="special">();</phrase>
<phrase role="keyword">explicit</phrase> <phrase role="identifier">fiber_specific_ptr</phrase><phrase role="special">(</phrase> <phrase role="keyword">void</phrase><phrase role="special">(*</phrase><phrase role="identifier">fn</phrase><phrase role="special">)(</phrase><phrase role="identifier">T</phrase><phrase role="special">*)</phrase> <phrase role="special">);</phrase>
<phrase role="special">~</phrase><phrase role="identifier">fiber_specific_ptr</phrase><phrase role="special">();</phrase>
<phrase role="identifier">fiber_specific_ptr</phrase><phrase role="special">(</phrase> <phrase role="identifier">fiber_specific_ptr</phrase> <phrase role="keyword">const</phrase><phrase role="special">&amp;)</phrase> <phrase role="special">=</phrase> <phrase role="keyword">delete</phrase><phrase role="special">;</phrase>
<phrase role="identifier">fiber_specific_ptr</phrase> <phrase role="special">&amp;</phrase> <phrase role="keyword">operator</phrase><phrase role="special">=(</phrase> <phrase role="identifier">fiber_specific_ptr</phrase> <phrase role="keyword">const</phrase><phrase role="special">&amp;)</phrase> <phrase role="special">=</phrase> <phrase role="keyword">delete</phrase><phrase role="special">;</phrase>
<phrase role="identifier">T</phrase> <phrase role="special">*</phrase> <phrase role="identifier">get</phrase><phrase role="special">()</phrase> <phrase role="keyword">const</phrase> <phrase role="keyword">noexcept</phrase><phrase role="special">;</phrase>
<phrase role="identifier">T</phrase> <phrase role="special">*</phrase> <phrase role="keyword">operator</phrase><phrase role="special">-&gt;()</phrase> <phrase role="keyword">const</phrase> <phrase role="keyword">noexcept</phrase><phrase role="special">;</phrase>
<phrase role="identifier">T</phrase> <phrase role="special">&amp;</phrase> <phrase role="keyword">operator</phrase><phrase role="special">*()</phrase> <phrase role="keyword">const</phrase> <phrase role="keyword">noexcept</phrase><phrase role="special">;</phrase>
<phrase role="identifier">T</phrase> <phrase role="special">*</phrase> <phrase role="identifier">release</phrase><phrase role="special">();</phrase>
<phrase role="keyword">void</phrase> <phrase role="identifier">reset</phrase><phrase role="special">(</phrase> <phrase role="identifier">T</phrase> <phrase role="special">*);</phrase>
<phrase role="special">};</phrase>
<phrase role="special">}}</phrase>
</programlisting>
<bridgehead renderas="sect3" id="fiber.fls.h2">
<phrase id="fiber.fls.constructor"/><link linkend="fiber.fls.constructor">Constructor</link>
</bridgehead>
<programlisting><phrase role="identifier">fiber_specific_ptr</phrase><phrase role="special">();</phrase>
<phrase role="keyword">explicit</phrase> <phrase role="identifier">fiber_specific_ptr</phrase><phrase role="special">(</phrase> <phrase role="keyword">void</phrase><phrase role="special">(*</phrase><phrase role="identifier">fn</phrase><phrase role="special">)(</phrase><phrase role="identifier">T</phrase><phrase role="special">*)</phrase> <phrase role="special">);</phrase>
</programlisting>
<variablelist>
<title></title>
<varlistentry>
<term>Requires:</term>
<listitem>
<para>
<code><phrase role="keyword">delete</phrase> <phrase role="keyword">this</phrase><phrase
role="special">-&gt;</phrase><phrase role="identifier">get</phrase><phrase
role="special">()</phrase></code> is well-formed; <code><phrase role="identifier">fn</phrase><phrase
role="special">(</phrase><phrase role="keyword">this</phrase><phrase
role="special">-&gt;</phrase><phrase role="identifier">get</phrase><phrase
role="special">())</phrase></code> does not throw
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>Effects:</term>
<listitem>
<para>
Construct a <link linkend="class_fiber_specific_ptr"><code>fiber_specific_ptr</code></link> object for storing
a pointer to an object of type <code><phrase role="identifier">T</phrase></code>
specific to each fiber. When <code><phrase role="identifier">reset</phrase><phrase
role="special">()</phrase></code> is called, or the fiber exits, <link linkend="class_fiber_specific_ptr"><code>fiber_specific_ptr</code></link> calls
<code><phrase role="identifier">fn</phrase><phrase role="special">(</phrase><phrase
role="keyword">this</phrase><phrase role="special">-&gt;</phrase><phrase
role="identifier">get</phrase><phrase role="special">())</phrase></code>.
If the no-arguments constructor is used, the default <code><phrase role="keyword">delete</phrase></code>-based
cleanup function will be used to destroy the fiber-local objects.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>Throws:</term>
<listitem>
<para>
<code><phrase role="identifier">fiber_error</phrase></code> if an error
occurs.
</para>
</listitem>
</varlistentry>
</variablelist>
<bridgehead renderas="sect3" id="fiber.fls.h3">
<phrase id="fiber.fls.destructor"/><link linkend="fiber.fls.destructor">Destructor</link>
</bridgehead>
<programlisting><phrase role="special">~</phrase><phrase role="identifier">fiber_specific_ptr</phrase><phrase role="special">();</phrase>
</programlisting>
<variablelist>
<title></title>
<varlistentry>
<term>Requires:</term>
<listitem>
<para>
All the fiber specific instances associated to this <link linkend="class_fiber_specific_ptr"><code>fiber_specific_ptr</code></link>
(except
maybe the one associated to this fiber) must be nullptr.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>Effects:</term>
<listitem>
<para>
Calls <code><phrase role="keyword">this</phrase><phrase role="special">-&gt;</phrase><phrase
role="identifier">reset</phrase><phrase role="special">()</phrase></code>
to clean up the associated value for the current fiber, and destroys
<code><phrase role="special">*</phrase><phrase role="keyword">this</phrase></code>.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>Remarks:</term>
<listitem>
<para>
The requirement is an implementation restriction. If the destructor promised
to delete instances for all fibers, the implementation would be forced
to maintain a list of all the fibers having an associated specific ptr,
which is against the goal of fiber specific data. In general, a <link linkend="class_fiber_specific_ptr"><code>fiber_specific_ptr</code></link> should
outlive the fibers that use it.
</para>
</listitem>
</varlistentry>
</variablelist>
<note>
<para>
Care needs to be taken to ensure that any fibers still running after an instance
of <link linkend="class_fiber_specific_ptr"><code>fiber_specific_ptr</code></link> has been destroyed do not call
any member functions on that instance.
</para>
</note>
<para>
<bridgehead renderas="sect4" id="fiber_specific_ptr_get_bridgehead">
<phrase id="fiber_specific_ptr_get"/>
<link linkend="fiber_specific_ptr_get">Member
function <code>get</code>()</link>
</bridgehead>
</para>
<programlisting><phrase role="identifier">T</phrase> <phrase role="special">*</phrase> <phrase role="identifier">get</phrase><phrase role="special">()</phrase> <phrase role="keyword">const</phrase> <phrase role="keyword">noexcept</phrase><phrase role="special">;</phrase>
</programlisting>
<variablelist>
<title></title>
<varlistentry>
<term>Returns:</term>
<listitem>
<para>
The pointer associated with the current fiber.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>Throws:</term>
<listitem>
<para>
Nothing.
</para>
</listitem>
</varlistentry>
</variablelist>
<note>
<para>
The initial value associated with an instance of <link linkend="class_fiber_specific_ptr"><code>fiber_specific_ptr</code></link> is
<code><phrase role="keyword">nullptr</phrase></code> for each fiber.
</para>
</note>
<para>
<bridgehead renderas="sect4" id="fiber_specific_ptr_operator_arrow_bridgehead">
<phrase id="fiber_specific_ptr_operator_arrow"/>
<link linkend="fiber_specific_ptr_operator_arrow">Member
function <code>operator-&gt;</code>()</link>
</bridgehead>
</para>
<programlisting><phrase role="identifier">T</phrase> <phrase role="special">*</phrase> <phrase role="keyword">operator</phrase><phrase role="special">-&gt;()</phrase> <phrase role="keyword">const</phrase> <phrase role="keyword">noexcept</phrase><phrase role="special">;</phrase>
</programlisting>
<variablelist>
<title></title>
<varlistentry>
<term>Requires:</term>
<listitem>
<para>
<code><phrase role="keyword">this</phrase><phrase role="special">-&gt;</phrase><phrase
role="identifier">get</phrase><phrase role="special">()</phrase></code>
is not <code><phrase role="keyword">nullptr</phrase></code>.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>Returns:</term>
<listitem>
<para>
<code><phrase role="keyword">this</phrase><phrase role="special">-&gt;</phrase><phrase
role="identifier">get</phrase><phrase role="special">()</phrase></code>
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>Throws:</term>
<listitem>
<para>
Nothing.
</para>
</listitem>
</varlistentry>
</variablelist>
<para>
<bridgehead renderas="sect4" id="fiber_specific_ptr_operator_star_bridgehead">
<phrase id="fiber_specific_ptr_operator_star"/>
<link linkend="fiber_specific_ptr_operator_star">Member
function <code>operator*</code>()</link>
</bridgehead>
</para>
<programlisting><phrase role="identifier">T</phrase> <phrase role="special">&amp;</phrase> <phrase role="keyword">operator</phrase><phrase role="special">*()</phrase> <phrase role="keyword">const</phrase> <phrase role="keyword">noexcept</phrase><phrase role="special">;</phrase>
</programlisting>
<variablelist>
<title></title>
<varlistentry>
<term>Requires:</term>
<listitem>
<para>
<code><phrase role="keyword">this</phrase><phrase role="special">-&gt;</phrase><phrase
role="identifier">get</phrase><phrase role="special">()</phrase></code>
is not <code><phrase role="keyword">nullptr</phrase></code>.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>Returns:</term>
<listitem>
<para>
<code><phrase role="special">*(</phrase><phrase role="keyword">this</phrase><phrase
role="special">-&gt;</phrase><phrase role="identifier">get</phrase><phrase
role="special">())</phrase></code>
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>Throws:</term>
<listitem>
<para>
Nothing.
</para>
</listitem>
</varlistentry>
</variablelist>
<para>
<bridgehead renderas="sect4" id="fiber_specific_ptr_release_bridgehead">
<phrase id="fiber_specific_ptr_release"/>
<link linkend="fiber_specific_ptr_release">Member
function <code>release</code>()</link>
</bridgehead>
</para>
<programlisting><phrase role="identifier">T</phrase> <phrase role="special">*</phrase> <phrase role="identifier">release</phrase><phrase role="special">();</phrase>
</programlisting>
<variablelist>
<title></title>
<varlistentry>
<term>Effects:</term>
<listitem>
<para>
Return <code><phrase role="keyword">this</phrase><phrase role="special">-&gt;</phrase><phrase
role="identifier">get</phrase><phrase role="special">()</phrase></code>
and store <code><phrase role="keyword">nullptr</phrase></code> as the
pointer associated with the current fiber without invoking the cleanup
function.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>Postcondition:</term>
<listitem>
<para>
<code><phrase role="keyword">this</phrase><phrase role="special">-&gt;</phrase><phrase
role="identifier">get</phrase><phrase role="special">()==</phrase><phrase
role="keyword">nullptr</phrase></code>
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>Throws:</term>
<listitem>
<para>
Nothing.
</para>
</listitem>
</varlistentry>
</variablelist>
<para>
<bridgehead renderas="sect4" id="fiber_specific_ptr_reset_bridgehead">
<phrase id="fiber_specific_ptr_reset"/>
<link linkend="fiber_specific_ptr_reset">Member
function <code>reset</code>()</link>
</bridgehead>
</para>
<programlisting><phrase role="keyword">void</phrase> <phrase role="identifier">reset</phrase><phrase role="special">(</phrase> <phrase role="identifier">T</phrase> <phrase role="special">*</phrase> <phrase role="identifier">new_value</phrase><phrase role="special">);</phrase>
</programlisting>
<variablelist>
<title></title>
<varlistentry>
<term>Effects:</term>
<listitem>
<para>
If <code><phrase role="keyword">this</phrase><phrase role="special">-&gt;</phrase><phrase
role="identifier">get</phrase><phrase role="special">()!=</phrase><phrase
role="identifier">new_value</phrase></code> and <code><phrase role="keyword">this</phrase><phrase
role="special">-&gt;</phrase><phrase role="identifier">get</phrase><phrase
role="special">()</phrase></code> is not <code><phrase role="keyword">nullptr</phrase></code>,
invoke <code><phrase role="keyword">delete</phrase> <phrase role="keyword">this</phrase><phrase
role="special">-&gt;</phrase><phrase role="identifier">get</phrase><phrase
role="special">()</phrase></code> or <code><phrase role="identifier">fn</phrase><phrase
role="special">(</phrase><phrase role="keyword">this</phrase><phrase
role="special">-&gt;</phrase><phrase role="identifier">get</phrase><phrase
role="special">())</phrase></code> as appropriate. Store <code><phrase
role="identifier">new_value</phrase></code> as the pointer associated
with the current fiber.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>Postcondition:</term>
<listitem>
<para>
<code><phrase role="keyword">this</phrase><phrase role="special">-&gt;</phrase><phrase
role="identifier">get</phrase><phrase role="special">()==</phrase><phrase
role="identifier">new_value</phrase></code>
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>Throws:</term>
<listitem>
<para>
Exception raised during cleanup of previous value.
</para>
</listitem>
</varlistentry>
</variablelist>
</section>
<section id="fiber.migration">
<title><anchor id="migration"/><link linkend="fiber.migration">Migrating fibers
between threads</link></title>
<bridgehead renderas="sect3" id="fiber.migration.h0">
<phrase id="fiber.migration.overview"/><link linkend="fiber.migration.overview">Overview</link>
</bridgehead>
<para>
Each fiber owns a stack and manages its execution state, including all registers
and CPU flags, the instruction pointer and the stack pointer. That means, in
general, a fiber is not bound to a specific thread.<footnote id="fiber.migration.f0">
<para>
The <quote>main</quote> fiber on each thread, that is, the fiber on which
the thread is launched, cannot migrate to any other thread. Also <emphasis
role="bold">Boost.Fiber</emphasis> implicitly creates a dispatcher fiber
for each thread &mdash; this cannot migrate either.
</para>
</footnote><superscript>,</superscript><footnote id="fiber.migration.f1">
<para>
Of course it would be problematic to migrate a fiber that relies on <link
linkend="thread_local_storage">thread-local storage</link>.
</para>
</footnote>
</para>
<para>
Migrating a fiber from a logical CPU with heavy workload to another logical
CPU with a lighter workload might speed up the overall execution. Note that
in the case of NUMA-architectures, it is not always advisable to migrate data
between threads. Suppose fiber <emphasis>f</emphasis> is running on logical
CPU <emphasis>cpu0</emphasis> which belongs to NUMA node <emphasis>node0</emphasis>.
The data of <emphasis>f</emphasis> are allocated on the physical memory located
at <emphasis>node0</emphasis>. Migrating the fiber from <emphasis>cpu0</emphasis>
to another logical CPU <emphasis>cpuX</emphasis> which is part of a different
NUMA node <emphasis>nodeX</emphasis> might reduce the performance of the application
due to increased latency of memory access.
</para>
<para>
Only fibers that are contained in <link linkend="class_algorithm"><code>algorithm</code></link>&#8217;s ready queue can
migrate between threads. You cannot migrate a running fiber, nor one that is
<link linkend="blocking"><emphasis>blocked</emphasis></link>. You cannot migrate
a fiber if its <link linkend="context_is_context"><code>context::is_context()</code></link> method returns <code><phrase
role="keyword">true</phrase></code> for <code><phrase role="identifier">pinned_context</phrase></code>.
</para>
<para>
In <emphasis role="bold">Boost.Fiber</emphasis> a fiber is migrated by invoking
<link linkend="context_detach"><code>context::detach()</code></link> on the thread from which the fiber migrates
and <link linkend="context_attach"><code>context::attach()</code></link> on the thread to which the fiber migrates.
</para>
<para>
Thus, fiber migration is accomplished by sharing state between instances of
a user-coded <link linkend="class_algorithm"><code>algorithm</code></link> implementation running on different threads.
The fiber&#8217;s original thread calls <link linkend="algorithm_awakened"><code>algorithm::awakened()</code></link>, passing
the fiber&#8217;s <link linkend="class_context"><code>context</code></link><literal>*</literal>. The <code><phrase role="identifier">awakened</phrase><phrase
role="special">()</phrase></code> implementation calls <link linkend="context_detach"><code>context::detach()</code></link>.
</para>
<para>
At some later point, when the same or a different thread calls <link linkend="algorithm_pick_next"><code>algorithm::pick_next()</code></link>,
the <code><phrase role="identifier">pick_next</phrase><phrase role="special">()</phrase></code>
implementation selects a ready fiber and calls <link linkend="context_attach"><code>context::attach()</code></link> on
it before returning it.
</para>
<para>
As stated above, a <code><phrase role="identifier">context</phrase></code>
for which <code><phrase role="identifier">is_context</phrase><phrase role="special">(</phrase><phrase
role="identifier">pinned_context</phrase><phrase role="special">)</phrase>
<phrase role="special">==</phrase> <phrase role="keyword">true</phrase></code>
must never be passed to either <link linkend="context_detach"><code>context::detach()</code></link> or <link linkend="context_attach"><code>context::attach()</code></link>.
It may only be returned from <code><phrase role="identifier">pick_next</phrase><phrase
role="special">()</phrase></code> called by the <emphasis>same</emphasis> thread
that passed that context to <code><phrase role="identifier">awakened</phrase><phrase
role="special">()</phrase></code>.
</para>
<bridgehead renderas="sect3" id="fiber.migration.h1">
<phrase id="fiber.migration.example_of_work_sharing"/><link linkend="fiber.migration.example_of_work_sharing">Example
of work sharing</link>
</bridgehead>
<para>
In the example <ulink url="../../examples/work_sharing.cpp">work_sharing.cpp</ulink>
multiple worker fibers are created on the main thread. Each fiber gets a character
as parameter at construction. This character is printed out ten times. Between
each iteration the fiber calls <link linkend="this_fiber_yield"><code>this_fiber::yield()</code></link>. That puts
the fiber in the ready queue of the fiber-scheduler <emphasis>shared_ready_queue</emphasis>,
running in the current thread. The next fiber ready to be executed is dequeued
from the shared ready queue and resumed by <emphasis>shared_ready_queue</emphasis>
running on <emphasis>any participating thread</emphasis>.
</para>
<para>
All instances of <emphasis>shared_ready_queue</emphasis> share one global concurrent
queue, used as ready queue. This mechanism shares all worker fibers between
all instances of <emphasis>shared_ready_queue</emphasis>, thus between all
participating threads.
</para>
<bridgehead renderas="sect3" id="fiber.migration.h2">
<phrase id="fiber.migration.setup_of_threads_and_fibers"/><link linkend="fiber.migration.setup_of_threads_and_fibers">Setup
of threads and fibers</link>
</bridgehead>
<para>
In <code><phrase role="identifier">main</phrase><phrase role="special">()</phrase></code>
the fiber-scheduler is installed and the worker fibers and the threads are
launched.
</para>
<para>
<programlisting><phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">fibers</phrase><phrase role="special">::</phrase><phrase role="identifier">use_scheduling_algorithm</phrase><phrase role="special">&lt;</phrase> <phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">fibers</phrase><phrase role="special">::</phrase><phrase role="identifier">algo</phrase><phrase role="special">::</phrase><phrase role="identifier">shared_work</phrase> <phrase role="special">&gt;();</phrase> <co id="fiber.migration.c0" linkends="fiber.migration.c1" />
<phrase role="keyword">for</phrase> <phrase role="special">(</phrase> <phrase role="keyword">char</phrase> <phrase role="identifier">c</phrase> <phrase role="special">:</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">string</phrase><phrase role="special">(</phrase><phrase role="string">&quot;abcdefghijklmnopqrstuvwxyz&quot;</phrase><phrase role="special">))</phrase> <phrase role="special">{</phrase> <co id="fiber.migration.c2" linkends="fiber.migration.c3" />
<phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">fibers</phrase><phrase role="special">::</phrase><phrase role="identifier">fiber</phrase><phrase role="special">([</phrase><phrase role="identifier">c</phrase><phrase role="special">](){</phrase> <phrase role="identifier">whatevah</phrase><phrase role="special">(</phrase> <phrase role="identifier">c</phrase><phrase role="special">);</phrase> <phrase role="special">}).</phrase><phrase role="identifier">detach</phrase><phrase role="special">();</phrase>
<phrase role="special">++</phrase><phrase role="identifier">fiber_count</phrase><phrase role="special">;</phrase> <co id="fiber.migration.c4" linkends="fiber.migration.c5" />
<phrase role="special">}</phrase>
<phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">fibers</phrase><phrase role="special">::</phrase><phrase role="identifier">detail</phrase><phrase role="special">::</phrase><phrase role="identifier">thread_barrier</phrase> <phrase role="identifier">b</phrase><phrase role="special">(</phrase> <phrase role="number">4</phrase><phrase role="special">);</phrase>
<phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">thread</phrase> <phrase role="identifier">threads</phrase><phrase role="special">[]</phrase> <phrase role="special">=</phrase> <phrase role="special">{</phrase> <co id="fiber.migration.c6" linkends="fiber.migration.c7" />
<phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">thread</phrase><phrase role="special">(</phrase> <phrase role="identifier">thread</phrase><phrase role="special">,</phrase> <phrase role="special">&amp;</phrase> <phrase role="identifier">b</phrase><phrase role="special">),</phrase>
<phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">thread</phrase><phrase role="special">(</phrase> <phrase role="identifier">thread</phrase><phrase role="special">,</phrase> <phrase role="special">&amp;</phrase> <phrase role="identifier">b</phrase><phrase role="special">),</phrase>
<phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">thread</phrase><phrase role="special">(</phrase> <phrase role="identifier">thread</phrase><phrase role="special">,</phrase> <phrase role="special">&amp;</phrase> <phrase role="identifier">b</phrase><phrase role="special">)</phrase>
<phrase role="special">};</phrase>
<phrase role="identifier">b</phrase><phrase role="special">.</phrase><phrase role="identifier">wait</phrase><phrase role="special">();</phrase> <co id="fiber.migration.c8" linkends="fiber.migration.c9" />
<phrase role="special">{</phrase>
<phrase role="identifier">lock_type</phrase><co id="fiber.migration.c10" linkends="fiber.migration.c11" /> <phrase role="identifier">lk</phrase><phrase role="special">(</phrase> <phrase role="identifier">mtx_count</phrase><phrase role="special">);</phrase>
<phrase role="identifier">cnd_count</phrase><phrase role="special">.</phrase><phrase role="identifier">wait</phrase><phrase role="special">(</phrase> <phrase role="identifier">lk</phrase><phrase role="special">,</phrase> <phrase role="special">[](){</phrase> <phrase role="keyword">return</phrase> <phrase role="number">0</phrase> <phrase role="special">==</phrase> <phrase role="identifier">fiber_count</phrase><phrase role="special">;</phrase> <phrase role="special">}</phrase> <phrase role="special">);</phrase> <co id="fiber.migration.c12" linkends="fiber.migration.c13" />
<phrase role="special">}</phrase> <co id="fiber.migration.c14" linkends="fiber.migration.c15" />
<phrase role="identifier">BOOST_ASSERT</phrase><phrase role="special">(</phrase> <phrase role="number">0</phrase> <phrase role="special">==</phrase> <phrase role="identifier">fiber_count</phrase><phrase role="special">);</phrase>
<phrase role="keyword">for</phrase> <phrase role="special">(</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">thread</phrase> <phrase role="special">&amp;</phrase> <phrase role="identifier">t</phrase> <phrase role="special">:</phrase> <phrase role="identifier">threads</phrase><phrase role="special">)</phrase> <phrase role="special">{</phrase> <co id="fiber.migration.c16" linkends="fiber.migration.c17" />
<phrase role="identifier">t</phrase><phrase role="special">.</phrase><phrase role="identifier">join</phrase><phrase role="special">();</phrase>
<phrase role="special">}</phrase>
</programlisting>
</para>
<calloutlist>
<callout arearefs="fiber.migration.c0" id="fiber.migration.c1">
<para>
Install the scheduling algorithm <code><phrase role="identifier">boost</phrase><phrase
role="special">::</phrase><phrase role="identifier">fibers</phrase><phrase
role="special">::</phrase><phrase role="identifier">algo</phrase><phrase
role="special">::</phrase><phrase role="identifier">shared_work</phrase></code>
in the main thread too, so each new fiber gets launched into the shared
pool.
</para>
</callout>
<callout arearefs="fiber.migration.c2" id="fiber.migration.c3">
<para>
Launch a number of worker fibers; each worker fiber picks up a character
that is passed as parameter to fiber-function <code><phrase role="identifier">whatevah</phrase></code>.
Each worker fiber gets detached.
</para>
</callout>
<callout arearefs="fiber.migration.c4" id="fiber.migration.c5">
<para>
Increment fiber counter for each new fiber.
</para>
</callout>
<callout arearefs="fiber.migration.c6" id="fiber.migration.c7">
<para>
Launch a couple of threads that join the work sharing.
</para>
</callout>
<callout arearefs="fiber.migration.c8" id="fiber.migration.c9">
<para>
sync with other threads: allow them to start processing
</para>
</callout>
<callout arearefs="fiber.migration.c10" id="fiber.migration.c11">
<para>
<code><phrase role="identifier">lock_type</phrase></code> is typedef'ed
as <ulink url="http://en.cppreference.com/w/cpp/thread/unique_lock"><code><phrase
role="identifier">std</phrase><phrase role="special">::</phrase><phrase
role="identifier">unique_lock</phrase></code></ulink>&lt; <ulink url="http://en.cppreference.com/w/cpp/thread/mutex"><code><phrase
role="identifier">std</phrase><phrase role="special">::</phrase><phrase
role="identifier">mutex</phrase></code></ulink> &gt;
</para>
</callout>
<callout arearefs="fiber.migration.c12" id="fiber.migration.c13">
<para>
Suspend main fiber and resume worker fibers in the meanwhile. Main fiber
gets resumed (e.g returns from <code><phrase role="identifier">condition_variable_any</phrase><phrase
role="special">::</phrase><phrase role="identifier">wait</phrase><phrase
role="special">()</phrase></code>) if all worker fibers are complete.
</para>
</callout>
<callout arearefs="fiber.migration.c14" id="fiber.migration.c15">
<para>
Releasing lock of mtx_count is required before joining the threads, otherwise
the other threads would be blocked inside condition_variable::wait() and
would never return (deadlock).
</para>
</callout>
<callout arearefs="fiber.migration.c16" id="fiber.migration.c17">
<para>
wait for threads to terminate
</para>
</callout>
</calloutlist>
<para>
The start of the threads is synchronized with a barrier. The main fiber of
each thread (including main thread) is suspended until all worker fibers are
complete. When the main fiber returns from <link linkend="condition_variable_wait"><code>condition_variable::wait()</code></link>,
the thread terminates: the main thread joins all other threads.
</para>
<para>
<programlisting><phrase role="keyword">void</phrase> <phrase role="identifier">thread</phrase><phrase role="special">(</phrase> <phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">fibers</phrase><phrase role="special">::</phrase><phrase role="identifier">detail</phrase><phrase role="special">::</phrase><phrase role="identifier">thread_barrier</phrase> <phrase role="special">*</phrase> <phrase role="identifier">b</phrase><phrase role="special">)</phrase> <phrase role="special">{</phrase>
<phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">ostringstream</phrase> <phrase role="identifier">buffer</phrase><phrase role="special">;</phrase>
<phrase role="identifier">buffer</phrase> <phrase role="special">&lt;&lt;</phrase> <phrase role="string">&quot;thread started &quot;</phrase> <phrase role="special">&lt;&lt;</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">this_thread</phrase><phrase role="special">::</phrase><phrase role="identifier">get_id</phrase><phrase role="special">()</phrase> <phrase role="special">&lt;&lt;</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">endl</phrase><phrase role="special">;</phrase>
<phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">cout</phrase> <phrase role="special">&lt;&lt;</phrase> <phrase role="identifier">buffer</phrase><phrase role="special">.</phrase><phrase role="identifier">str</phrase><phrase role="special">()</phrase> <phrase role="special">&lt;&lt;</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">flush</phrase><phrase role="special">;</phrase>
<phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">fibers</phrase><phrase role="special">::</phrase><phrase role="identifier">use_scheduling_algorithm</phrase><phrase role="special">&lt;</phrase> <phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">fibers</phrase><phrase role="special">::</phrase><phrase role="identifier">algo</phrase><phrase role="special">::</phrase><phrase role="identifier">shared_work</phrase> <phrase role="special">&gt;();</phrase> <co id="fiber.migration.c18" linkends="fiber.migration.c19" />
<phrase role="identifier">b</phrase><phrase role="special">-&gt;</phrase><phrase role="identifier">wait</phrase><phrase role="special">();</phrase> <co id="fiber.migration.c20" linkends="fiber.migration.c21" />
<phrase role="identifier">lock_type</phrase> <phrase role="identifier">lk</phrase><phrase role="special">(</phrase> <phrase role="identifier">mtx_count</phrase><phrase role="special">);</phrase>
<phrase role="identifier">cnd_count</phrase><phrase role="special">.</phrase><phrase role="identifier">wait</phrase><phrase role="special">(</phrase> <phrase role="identifier">lk</phrase><phrase role="special">,</phrase> <phrase role="special">[](){</phrase> <phrase role="keyword">return</phrase> <phrase role="number">0</phrase> <phrase role="special">==</phrase> <phrase role="identifier">fiber_count</phrase><phrase role="special">;</phrase> <phrase role="special">}</phrase> <phrase role="special">);</phrase> <co id="fiber.migration.c22" linkends="fiber.migration.c23" />
<phrase role="identifier">BOOST_ASSERT</phrase><phrase role="special">(</phrase> <phrase role="number">0</phrase> <phrase role="special">==</phrase> <phrase role="identifier">fiber_count</phrase><phrase role="special">);</phrase>
<phrase role="special">}</phrase>
</programlisting>
</para>
<calloutlist>
<callout arearefs="fiber.migration.c18" id="fiber.migration.c19">
<para>
Install the scheduling algorithm <code><phrase role="identifier">boost</phrase><phrase
role="special">::</phrase><phrase role="identifier">fibers</phrase><phrase
role="special">::</phrase><phrase role="identifier">algo</phrase><phrase
role="special">::</phrase><phrase role="identifier">shared_work</phrase></code>
in order to join the work sharing.
</para>
</callout>
<callout arearefs="fiber.migration.c20" id="fiber.migration.c21">
<para>
sync with other threads: allow them to start processing
</para>
</callout>
<callout arearefs="fiber.migration.c22" id="fiber.migration.c23">
<para>
Suspend main fiber and resume worker fibers in the meanwhile. Main fiber
gets resumed (e.g returns from <code><phrase role="identifier">condition_variable_any</phrase><phrase
role="special">::</phrase><phrase role="identifier">wait</phrase><phrase
role="special">()</phrase></code>) if all worker fibers are complete.
</para>
</callout>
</calloutlist>
<para>
Each worker fiber executes function <code><phrase role="identifier">whatevah</phrase><phrase
role="special">()</phrase></code> with character <code><phrase role="identifier">me</phrase></code>
as parameter. The fiber yields in a loop and prints out a message if it was
migrated to another thread.
</para>
<para>
<programlisting><phrase role="keyword">void</phrase> <phrase role="identifier">whatevah</phrase><phrase role="special">(</phrase> <phrase role="keyword">char</phrase> <phrase role="identifier">me</phrase><phrase role="special">)</phrase> <phrase role="special">{</phrase>
<phrase role="keyword">try</phrase> <phrase role="special">{</phrase>
<phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">thread</phrase><phrase role="special">::</phrase><phrase role="identifier">id</phrase> <phrase role="identifier">my_thread</phrase> <phrase role="special">=</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">this_thread</phrase><phrase role="special">::</phrase><phrase role="identifier">get_id</phrase><phrase role="special">();</phrase> <co id="fiber.migration.c24" linkends="fiber.migration.c25" />
<phrase role="special">{</phrase>
<phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">ostringstream</phrase> <phrase role="identifier">buffer</phrase><phrase role="special">;</phrase>
<phrase role="identifier">buffer</phrase> <phrase role="special">&lt;&lt;</phrase> <phrase role="string">&quot;fiber &quot;</phrase> <phrase role="special">&lt;&lt;</phrase> <phrase role="identifier">me</phrase> <phrase role="special">&lt;&lt;</phrase> <phrase role="string">&quot; started on thread &quot;</phrase> <phrase role="special">&lt;&lt;</phrase> <phrase role="identifier">my_thread</phrase> <phrase role="special">&lt;&lt;</phrase> <phrase role="char">'\n'</phrase><phrase role="special">;</phrase>
<phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">cout</phrase> <phrase role="special">&lt;&lt;</phrase> <phrase role="identifier">buffer</phrase><phrase role="special">.</phrase><phrase role="identifier">str</phrase><phrase role="special">()</phrase> <phrase role="special">&lt;&lt;</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">flush</phrase><phrase role="special">;</phrase>
<phrase role="special">}</phrase>
<phrase role="keyword">for</phrase> <phrase role="special">(</phrase> <phrase role="keyword">unsigned</phrase> <phrase role="identifier">i</phrase> <phrase role="special">=</phrase> <phrase role="number">0</phrase><phrase role="special">;</phrase> <phrase role="identifier">i</phrase> <phrase role="special">&lt;</phrase> <phrase role="number">10</phrase><phrase role="special">;</phrase> <phrase role="special">++</phrase><phrase role="identifier">i</phrase><phrase role="special">)</phrase> <phrase role="special">{</phrase> <co id="fiber.migration.c26" linkends="fiber.migration.c27" />
<phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">this_fiber</phrase><phrase role="special">::</phrase><phrase role="identifier">yield</phrase><phrase role="special">();</phrase> <co id="fiber.migration.c28" linkends="fiber.migration.c29" />
<phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">thread</phrase><phrase role="special">::</phrase><phrase role="identifier">id</phrase> <phrase role="identifier">new_thread</phrase> <phrase role="special">=</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">this_thread</phrase><phrase role="special">::</phrase><phrase role="identifier">get_id</phrase><phrase role="special">();</phrase> <co id="fiber.migration.c30" linkends="fiber.migration.c31" />
<phrase role="keyword">if</phrase> <phrase role="special">(</phrase> <phrase role="identifier">new_thread</phrase> <phrase role="special">!=</phrase> <phrase role="identifier">my_thread</phrase><phrase role="special">)</phrase> <phrase role="special">{</phrase> <co id="fiber.migration.c32" linkends="fiber.migration.c33" />
<phrase role="identifier">my_thread</phrase> <phrase role="special">=</phrase> <phrase role="identifier">new_thread</phrase><phrase role="special">;</phrase>
<phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">ostringstream</phrase> <phrase role="identifier">buffer</phrase><phrase role="special">;</phrase>
<phrase role="identifier">buffer</phrase> <phrase role="special">&lt;&lt;</phrase> <phrase role="string">&quot;fiber &quot;</phrase> <phrase role="special">&lt;&lt;</phrase> <phrase role="identifier">me</phrase> <phrase role="special">&lt;&lt;</phrase> <phrase role="string">&quot; switched to thread &quot;</phrase> <phrase role="special">&lt;&lt;</phrase> <phrase role="identifier">my_thread</phrase> <phrase role="special">&lt;&lt;</phrase> <phrase role="char">'\n'</phrase><phrase role="special">;</phrase>
<phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">cout</phrase> <phrase role="special">&lt;&lt;</phrase> <phrase role="identifier">buffer</phrase><phrase role="special">.</phrase><phrase role="identifier">str</phrase><phrase role="special">()</phrase> <phrase role="special">&lt;&lt;</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">flush</phrase><phrase role="special">;</phrase>
<phrase role="special">}</phrase>
<phrase role="special">}</phrase>
<phrase role="special">}</phrase> <phrase role="keyword">catch</phrase> <phrase role="special">(</phrase> <phrase role="special">...</phrase> <phrase role="special">)</phrase> <phrase role="special">{</phrase>
<phrase role="special">}</phrase>
<phrase role="identifier">lock_type</phrase> <phrase role="identifier">lk</phrase><phrase role="special">(</phrase> <phrase role="identifier">mtx_count</phrase><phrase role="special">);</phrase>
<phrase role="keyword">if</phrase> <phrase role="special">(</phrase> <phrase role="number">0</phrase> <phrase role="special">==</phrase> <phrase role="special">--</phrase><phrase role="identifier">fiber_count</phrase><phrase role="special">)</phrase> <phrase role="special">{</phrase> <co id="fiber.migration.c34" linkends="fiber.migration.c35" />
<phrase role="identifier">lk</phrase><phrase role="special">.</phrase><phrase role="identifier">unlock</phrase><phrase role="special">();</phrase>
<phrase role="identifier">cnd_count</phrase><phrase role="special">.</phrase><phrase role="identifier">notify_all</phrase><phrase role="special">();</phrase> <co id="fiber.migration.c36" linkends="fiber.migration.c37" />
<phrase role="special">}</phrase>
<phrase role="special">}</phrase>
</programlisting>
</para>
<calloutlist>
<callout arearefs="fiber.migration.c24" id="fiber.migration.c25">
<para>
get ID of initial thread
</para>
</callout>
<callout arearefs="fiber.migration.c26" id="fiber.migration.c27">
<para>
loop ten times
</para>
</callout>
<callout arearefs="fiber.migration.c28" id="fiber.migration.c29">
<para>
yield to other fibers
</para>
</callout>
<callout arearefs="fiber.migration.c30" id="fiber.migration.c31">
<para>
get ID of current thread
</para>
</callout>
<callout arearefs="fiber.migration.c32" id="fiber.migration.c33">
<para>
test if fiber was migrated to another thread
</para>
</callout>
<callout arearefs="fiber.migration.c34" id="fiber.migration.c35">
<para>
Decrement fiber counter for each completed fiber.
</para>
</callout>
<callout arearefs="fiber.migration.c36" id="fiber.migration.c37">
<para>
Notify all fibers waiting on <code><phrase role="identifier">cnd_count</phrase></code>.
</para>
</callout>
</calloutlist>
<bridgehead renderas="sect3" id="fiber.migration.h3">
<phrase id="fiber.migration.scheduling_fibers"/><link linkend="fiber.migration.scheduling_fibers">Scheduling
fibers</link>
</bridgehead>
<para>
The fiber scheduler <code><phrase role="identifier">shared_ready_queue</phrase></code>
is like <code><phrase role="identifier">round_robin</phrase></code>, except
that it shares a common ready queue among all participating threads. A thread
participates in this pool by executing <link linkend="use_scheduling_algorithm"><code>use_scheduling_algorithm()</code></link>
before
any other <emphasis role="bold">Boost.Fiber</emphasis> operation.
</para>
<para>
The important point about the ready queue is that it&#8217;s a class static, common
to all instances of shared_ready_queue. Fibers that are enqueued via <link linkend="algorithm_awakened"><code>algorithm::awakened()</code></link> (fibers
that are ready to be resumed) are thus available to all threads. It is required
to reserve a separate, scheduler-specific queue for the thread&#8217;s main fiber
and dispatcher fibers: these may <emphasis>not</emphasis> be shared between
threads! When we&#8217;re passed either of these fibers, push it there instead of
in the shared queue: it would be Bad News for thread B to retrieve and attempt
to execute thread A&#8217;s main fiber.
</para>
<para>
[awakened_ws]
</para>
<para>
When <link linkend="algorithm_pick_next"><code>algorithm::pick_next()</code></link> gets called inside one thread,
a fiber is dequeued from <emphasis>rqueue_</emphasis> and will be resumed in
that thread.
</para>
<para>
[pick_next_ws]
</para>
<para>
The source code above is found in <ulink url="../../examples/work_sharing.cpp">work_sharing.cpp</ulink>.
</para>
</section>
<section id="fiber.callbacks">
<title><anchor id="callbacks"/><link linkend="fiber.callbacks">Integrating Fibers
with Asynchronous Callbacks</link></title>
<section id="fiber.callbacks.overview">
<title><link linkend="fiber.callbacks.overview">Overview</link></title>
<para>
One of the primary benefits of <emphasis role="bold">Boost.Fiber</emphasis>
is the ability to use asynchronous operations for efficiency, while at the
same time structuring the calling code <emphasis>as if</emphasis> the operations
were synchronous. Asynchronous operations provide completion notification
in a variety of ways, but most involve a callback function of some kind.
This section discusses tactics for interfacing <emphasis role="bold">Boost.Fiber</emphasis>
with an arbitrary async operation.
</para>
<para>
For purposes of illustration, consider the following hypothetical API:
</para>
<para>
<programlisting><phrase role="keyword">class</phrase> <phrase role="identifier">AsyncAPI</phrase> <phrase role="special">{</phrase>
<phrase role="keyword">public</phrase><phrase role="special">:</phrase>
<phrase role="comment">// constructor acquires some resource that can be read and written</phrase>
<phrase role="identifier">AsyncAPI</phrase><phrase role="special">();</phrase>
<phrase role="comment">// callbacks accept an int error code; 0 == success</phrase>
<phrase role="keyword">typedef</phrase> <phrase role="keyword">int</phrase> <phrase role="identifier">errorcode</phrase><phrase role="special">;</phrase>
<phrase role="comment">// write callback only needs to indicate success or failure</phrase>
<phrase role="keyword">template</phrase><phrase role="special">&lt;</phrase> <phrase role="keyword">typename</phrase> <phrase role="identifier">Fn</phrase> <phrase role="special">&gt;</phrase>
<phrase role="keyword">void</phrase> <phrase role="identifier">init_write</phrase><phrase role="special">(</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">string</phrase> <phrase role="keyword">const</phrase><phrase role="special">&amp;</phrase> <phrase role="identifier">data</phrase><phrase role="special">,</phrase> <phrase role="identifier">Fn</phrase> <phrase role="special">&amp;&amp;</phrase> <phrase role="identifier">callback</phrase><phrase role="special">);</phrase>
<phrase role="comment">// read callback needs to accept both errorcode and data</phrase>
<phrase role="keyword">template</phrase><phrase role="special">&lt;</phrase> <phrase role="keyword">typename</phrase> <phrase role="identifier">Fn</phrase> <phrase role="special">&gt;</phrase>
<phrase role="keyword">void</phrase> <phrase role="identifier">init_read</phrase><phrase role="special">(</phrase> <phrase role="identifier">Fn</phrase> <phrase role="special">&amp;&amp;</phrase> <phrase role="identifier">callback</phrase><phrase role="special">);</phrase>
<phrase role="comment">// ... other operations ...</phrase>
<phrase role="special">};</phrase>
</programlisting>
</para>
<para>
The significant points about each of <code><phrase role="identifier">init_write</phrase><phrase
role="special">()</phrase></code> and <code><phrase role="identifier">init_read</phrase><phrase
role="special">()</phrase></code> are:
</para>
<itemizedlist>
<listitem>
<simpara>
The <code><phrase role="identifier">AsyncAPI</phrase></code> method only
initiates the operation. It returns immediately, while the requested
operation is still pending.
</simpara>
</listitem>
<listitem>
<simpara>
The method accepts a callback. When the operation completes, the callback
is called with relevant parameters (error code, data if applicable).
</simpara>
</listitem>
</itemizedlist>
<para>
We would like to wrap these asynchronous methods in functions that appear
synchronous by blocking the calling fiber until the operation completes.
This lets us use the wrapper function&#8217;s return value to deliver relevant data.
</para>
<tip>
<para>
<link linkend="class_promise"><code>promise&lt;&gt;</code></link> and <link linkend="class_future"><code>future&lt;&gt;</code></link> are your friends
here.
</para>
</tip>
</section>
<section id="fiber.callbacks.return_errorcode">
<title><link linkend="fiber.callbacks.return_errorcode">Return Errorcode</link></title>
<para>
The <code><phrase role="identifier">AsyncAPI</phrase><phrase role="special">::</phrase><phrase
role="identifier">init_write</phrase><phrase role="special">()</phrase></code>
callback passes only an <code><phrase role="identifier">errorcode</phrase></code>.
If we simply want the blocking wrapper to return that <code><phrase role="identifier">errorcode</phrase></code>,
this is an extremely straightforward use of <link linkend="class_promise"><code>promise&lt;&gt;</code></link> and
<link linkend="class_future"><code>future&lt;&gt;</code></link>:
</para>
<para>
<programlisting><phrase role="identifier">AsyncAPI</phrase><phrase role="special">::</phrase><phrase role="identifier">errorcode</phrase> <phrase role="identifier">write_ec</phrase><phrase role="special">(</phrase> <phrase role="identifier">AsyncAPI</phrase> <phrase role="special">&amp;</phrase> <phrase role="identifier">api</phrase><phrase role="special">,</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">string</phrase> <phrase role="keyword">const</phrase><phrase role="special">&amp;</phrase> <phrase role="identifier">data</phrase><phrase role="special">)</phrase> <phrase role="special">{</phrase>
<phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">fibers</phrase><phrase role="special">::</phrase><phrase role="identifier">promise</phrase><phrase role="special">&lt;</phrase> <phrase role="identifier">AsyncAPI</phrase><phrase role="special">::</phrase><phrase role="identifier">errorcode</phrase> <phrase role="special">&gt;</phrase> <phrase role="identifier">promise</phrase><phrase role="special">;</phrase>
<phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">fibers</phrase><phrase role="special">::</phrase><phrase role="identifier">future</phrase><phrase role="special">&lt;</phrase> <phrase role="identifier">AsyncAPI</phrase><phrase role="special">::</phrase><phrase role="identifier">errorcode</phrase> <phrase role="special">&gt;</phrase> <phrase role="identifier">future</phrase><phrase role="special">(</phrase> <phrase role="identifier">promise</phrase><phrase role="special">.</phrase><phrase role="identifier">get_future</phrase><phrase role="special">()</phrase> <phrase role="special">);</phrase>
<phrase role="comment">// In general, even though we block waiting for future::get() and therefore</phrase>
<phrase role="comment">// won't destroy 'promise' until promise::set_value() has been called, we</phrase>
<phrase role="comment">// are advised that with threads it's possible for ~promise() to be</phrase>
<phrase role="comment">// entered before promise::set_value() has returned. While that shouldn't</phrase>
<phrase role="comment">// happen with fibers::promise, a robust way to deal with the lifespan</phrase>
<phrase role="comment">// issue is to bind 'promise' into our lambda. Since promise is move-only,</phrase>
<phrase role="comment">// use initialization capture.</phrase>
<phrase role="preprocessor">#if</phrase> <phrase role="special">!</phrase> <phrase role="identifier">defined</phrase><phrase role="special">(</phrase><phrase role="identifier">BOOST_NO_CXX14_INITIALIZED_LAMBDA_CAPTURES</phrase><phrase role="special">)</phrase>
<phrase role="identifier">api</phrase><phrase role="special">.</phrase><phrase role="identifier">init_write</phrase><phrase role="special">(</phrase>
<phrase role="identifier">data</phrase><phrase role="special">,</phrase>
<phrase role="special">[</phrase><phrase role="identifier">promise</phrase><phrase role="special">=</phrase><phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">move</phrase><phrase role="special">(</phrase> <phrase role="identifier">promise</phrase><phrase role="special">)](</phrase> <phrase role="identifier">AsyncAPI</phrase><phrase role="special">::</phrase><phrase role="identifier">errorcode</phrase> <phrase role="identifier">ec</phrase><phrase role="special">)</phrase> <phrase role="keyword">mutable</phrase> <phrase role="special">{</phrase>
<phrase role="identifier">promise</phrase><phrase role="special">.</phrase><phrase role="identifier">set_value</phrase><phrase role="special">(</phrase> <phrase role="identifier">ec</phrase><phrase role="special">);</phrase>
<phrase role="special">});</phrase>
<phrase role="preprocessor">#else</phrase> <phrase role="comment">// defined(BOOST_NO_CXX14_INITIALIZED_LAMBDA_CAPTURES)</phrase>
<phrase role="identifier">api</phrase><phrase role="special">.</phrase><phrase role="identifier">init_write</phrase><phrase role="special">(</phrase>
<phrase role="identifier">data</phrase><phrase role="special">,</phrase>
<phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">bind</phrase><phrase role="special">([](</phrase><phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">fibers</phrase><phrase role="special">::</phrase><phrase role="identifier">promise</phrase><phrase role="special">&lt;</phrase> <phrase role="identifier">AsyncAPI</phrase><phrase role="special">::</phrase><phrase role="identifier">errorcode</phrase> <phrase role="special">&gt;</phrase> <phrase role="special">&amp;</phrase> <phrase role="identifier">promise</phrase><phrase role="special">,</phrase>
<phrase role="identifier">AsyncAPI</phrase><phrase role="special">::</phrase><phrase role="identifier">errorcode</phrase> <phrase role="identifier">ec</phrase><phrase role="special">)</phrase> <phrase role="special">{</phrase>
<phrase role="identifier">promise</phrase><phrase role="special">.</phrase><phrase role="identifier">set_value</phrase><phrase role="special">(</phrase> <phrase role="identifier">ec</phrase><phrase role="special">);</phrase>
<phrase role="special">},</phrase>
<phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">move</phrase><phrase role="special">(</phrase> <phrase role="identifier">promise</phrase><phrase role="special">),</phrase>
<phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">placeholders</phrase><phrase role="special">::</phrase><phrase role="identifier">_1</phrase><phrase role="special">)</phrase> <phrase role="special">);</phrase>
<phrase role="preprocessor">#endif</phrase> <phrase role="comment">// BOOST_NO_CXX14_INITIALIZED_LAMBDA_CAPTURES</phrase>
<phrase role="keyword">return</phrase> <phrase role="identifier">future</phrase><phrase role="special">.</phrase><phrase role="identifier">get</phrase><phrase role="special">();</phrase>
<phrase role="special">}</phrase>
</programlisting>
</para>
<para>
All we have to do is:
</para>
<orderedlist>
<listitem>
<simpara>
Instantiate a <code><phrase role="identifier">promise</phrase><phrase
role="special">&lt;&gt;</phrase></code> of correct type.
</simpara>
</listitem>
<listitem>
<simpara>
Obtain its <code><phrase role="identifier">future</phrase><phrase role="special">&lt;&gt;</phrase></code>.
</simpara>
</listitem>
<listitem>
<simpara>
Arrange for the callback to call <link linkend="promise_set_value"><code>promise::set_value()</code></link>.
</simpara>
</listitem>
<listitem>
<simpara>
Block on <link linkend="future_get"><code>future::get()</code></link>.
</simpara>
</listitem>
</orderedlist>
<note>
<para>
This tactic for resuming a pending fiber works even if the callback is
called on a different thread than the one on which the initiating fiber
is running. In fact, <ulink url="../../examples/adapt_callbacks.cpp">the
example program&#8217;s</ulink> dummy <code><phrase role="identifier">AsyncAPI</phrase></code>
implementation illustrates that: it simulates async I/O by launching a
new thread that sleeps briefly and then calls the relevant callback.
</para>
</note>
</section>
<section id="fiber.callbacks.success_or_exception">
<title><link linkend="fiber.callbacks.success_or_exception">Success or Exception</link></title>
<para>
A wrapper more aligned with modern C++ practice would use an exception, rather
than an <code><phrase role="identifier">errorcode</phrase></code>, to communicate
failure to its caller. This is straightforward to code in terms of <code><phrase
role="identifier">write_ec</phrase><phrase role="special">()</phrase></code>:
</para>
<para>
<programlisting><phrase role="keyword">void</phrase> <phrase role="identifier">write</phrase><phrase role="special">(</phrase> <phrase role="identifier">AsyncAPI</phrase> <phrase role="special">&amp;</phrase> <phrase role="identifier">api</phrase><phrase role="special">,</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">string</phrase> <phrase role="keyword">const</phrase><phrase role="special">&amp;</phrase> <phrase role="identifier">data</phrase><phrase role="special">)</phrase> <phrase role="special">{</phrase>
<phrase role="identifier">AsyncAPI</phrase><phrase role="special">::</phrase><phrase role="identifier">errorcode</phrase> <phrase role="identifier">ec</phrase> <phrase role="special">=</phrase> <phrase role="identifier">write_ec</phrase><phrase role="special">(</phrase> <phrase role="identifier">api</phrase><phrase role="special">,</phrase> <phrase role="identifier">data</phrase><phrase role="special">);</phrase>
<phrase role="keyword">if</phrase> <phrase role="special">(</phrase> <phrase role="identifier">ec</phrase><phrase role="special">)</phrase> <phrase role="special">{</phrase>
<phrase role="keyword">throw</phrase> <phrase role="identifier">make_exception</phrase><phrase role="special">(</phrase><phrase role="string">&quot;write&quot;</phrase><phrase role="special">,</phrase> <phrase role="identifier">ec</phrase><phrase role="special">);</phrase>
<phrase role="special">}</phrase>
<phrase role="special">}</phrase>
</programlisting>
</para>
<para>
The point is that since each fiber has its own stack, you need not repeat
messy boilerplate: normal encapsulation works.
</para>
</section>
<section id="fiber.callbacks.return_errorcode_or_data">
<title><link linkend="fiber.callbacks.return_errorcode_or_data">Return Errorcode
or Data</link></title>
<para>
Things get a bit more interesting when the async operation&#8217;s callback passes
multiple data items of interest. One approach would be to use <code><phrase
role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">pair</phrase><phrase
role="special">&lt;&gt;</phrase></code> to capture both:
</para>
<para>
<programlisting><phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">pair</phrase><phrase role="special">&lt;</phrase> <phrase role="identifier">AsyncAPI</phrase><phrase role="special">::</phrase><phrase role="identifier">errorcode</phrase><phrase role="special">,</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">string</phrase> <phrase role="special">&gt;</phrase> <phrase role="identifier">read_ec</phrase><phrase role="special">(</phrase> <phrase role="identifier">AsyncAPI</phrase> <phrase role="special">&amp;</phrase> <phrase role="identifier">api</phrase><phrase role="special">)</phrase> <phrase role="special">{</phrase>
<phrase role="keyword">typedef</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">pair</phrase><phrase role="special">&lt;</phrase> <phrase role="identifier">AsyncAPI</phrase><phrase role="special">::</phrase><phrase role="identifier">errorcode</phrase><phrase role="special">,</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">string</phrase> <phrase role="special">&gt;</phrase> <phrase role="identifier">result_pair</phrase><phrase role="special">;</phrase>
<phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">fibers</phrase><phrase role="special">::</phrase><phrase role="identifier">promise</phrase><phrase role="special">&lt;</phrase> <phrase role="identifier">result_pair</phrase> <phrase role="special">&gt;</phrase> <phrase role="identifier">promise</phrase><phrase role="special">;</phrase>
<phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">fibers</phrase><phrase role="special">::</phrase><phrase role="identifier">future</phrase><phrase role="special">&lt;</phrase> <phrase role="identifier">result_pair</phrase> <phrase role="special">&gt;</phrase> <phrase role="identifier">future</phrase><phrase role="special">(</phrase> <phrase role="identifier">promise</phrase><phrase role="special">.</phrase><phrase role="identifier">get_future</phrase><phrase role="special">()</phrase> <phrase role="special">);</phrase>
<phrase role="comment">// We promise that both 'promise' and 'future' will survive until our</phrase>
<phrase role="comment">// lambda has been called.</phrase>
<phrase role="preprocessor">#if</phrase> <phrase role="special">!</phrase> <phrase role="identifier">defined</phrase><phrase role="special">(</phrase><phrase role="identifier">BOOST_NO_CXX14_INITIALIZED_LAMBDA_CAPTURES</phrase><phrase role="special">)</phrase>
<phrase role="identifier">api</phrase><phrase role="special">.</phrase><phrase role="identifier">init_read</phrase><phrase role="special">([</phrase><phrase role="identifier">promise</phrase><phrase role="special">=</phrase><phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">move</phrase><phrase role="special">(</phrase> <phrase role="identifier">promise</phrase><phrase role="special">)](</phrase> <phrase role="identifier">AsyncAPI</phrase><phrase role="special">::</phrase><phrase role="identifier">errorcode</phrase> <phrase role="identifier">ec</phrase><phrase role="special">,</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">string</phrase> <phrase role="keyword">const</phrase><phrase role="special">&amp;</phrase> <phrase role="identifier">data</phrase><phrase role="special">)</phrase> <phrase role="keyword">mutable</phrase> <phrase role="special">{</phrase>
<phrase role="identifier">promise</phrase><phrase role="special">.</phrase><phrase role="identifier">set_value</phrase><phrase role="special">(</phrase> <phrase role="identifier">result_pair</phrase><phrase role="special">(</phrase> <phrase role="identifier">ec</phrase><phrase role="special">,</phrase> <phrase role="identifier">data</phrase><phrase role="special">)</phrase> <phrase role="special">);</phrase>
<phrase role="special">});</phrase>
<phrase role="preprocessor">#else</phrase> <phrase role="comment">// defined(BOOST_NO_CXX14_INITIALIZED_LAMBDA_CAPTURES)</phrase>
<phrase role="identifier">api</phrase><phrase role="special">.</phrase><phrase role="identifier">init_read</phrase><phrase role="special">(</phrase>
<phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">bind</phrase><phrase role="special">([](</phrase> <phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">fibers</phrase><phrase role="special">::</phrase><phrase role="identifier">promise</phrase><phrase role="special">&lt;</phrase> <phrase role="identifier">result_pair</phrase> <phrase role="special">&gt;</phrase> <phrase role="special">&amp;</phrase> <phrase role="identifier">promise</phrase><phrase role="special">,</phrase>
<phrase role="identifier">AsyncAPI</phrase><phrase role="special">::</phrase><phrase role="identifier">errorcode</phrase> <phrase role="identifier">ec</phrase><phrase role="special">,</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">string</phrase> <phrase role="keyword">const</phrase><phrase role="special">&amp;</phrase> <phrase role="identifier">data</phrase><phrase role="special">)</phrase> <phrase role="keyword">mutable</phrase> <phrase role="special">{</phrase>
<phrase role="identifier">promise</phrase><phrase role="special">.</phrase><phrase role="identifier">set_value</phrase><phrase role="special">(</phrase> <phrase role="identifier">result_pair</phrase><phrase role="special">(</phrase> <phrase role="identifier">ec</phrase><phrase role="special">,</phrase> <phrase role="identifier">data</phrase><phrase role="special">)</phrase> <phrase role="special">);</phrase>
<phrase role="special">},</phrase>
<phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">move</phrase><phrase role="special">(</phrase> <phrase role="identifier">promise</phrase><phrase role="special">),</phrase>
<phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">placeholders</phrase><phrase role="special">::</phrase><phrase role="identifier">_1</phrase><phrase role="special">,</phrase>
<phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">placeholders</phrase><phrase role="special">::</phrase><phrase role="identifier">_2</phrase><phrase role="special">)</phrase> <phrase role="special">);</phrase>
<phrase role="preprocessor">#endif</phrase> <phrase role="comment">// BOOST_NO_CXX14_INITIALIZED_LAMBDA_CAPTURES</phrase>
<phrase role="keyword">return</phrase> <phrase role="identifier">future</phrase><phrase role="special">.</phrase><phrase role="identifier">get</phrase><phrase role="special">();</phrase>
<phrase role="special">}</phrase>
</programlisting>
</para>
<para>
Once you bundle the interesting data in <code><phrase role="identifier">std</phrase><phrase
role="special">::</phrase><phrase role="identifier">pair</phrase><phrase
role="special">&lt;&gt;</phrase></code>, the code is effectively identical
to <code><phrase role="identifier">write_ec</phrase><phrase role="special">()</phrase></code>.
You can call it like this:
</para>
<para>
<programlisting><phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">tie</phrase><phrase role="special">(</phrase> <phrase role="identifier">ec</phrase><phrase role="special">,</phrase> <phrase role="identifier">data</phrase><phrase role="special">)</phrase> <phrase role="special">=</phrase> <phrase role="identifier">read_ec</phrase><phrase role="special">(</phrase> <phrase role="identifier">api</phrase><phrase role="special">);</phrase>
</programlisting>
</para>
</section>
<section id="fiber.callbacks.data_or_exception">
<title><anchor id="Data_or_Exception"/><link linkend="fiber.callbacks.data_or_exception">Data
or Exception</link></title>
<para>
But a more natural API for a function that obtains data is to return only
the data on success, throwing an exception on error.
</para>
<para>
As with <code><phrase role="identifier">write</phrase><phrase role="special">()</phrase></code>
above, it&#8217;s certainly possible to code a <code><phrase role="identifier">read</phrase><phrase
role="special">()</phrase></code> wrapper in terms of <code><phrase role="identifier">read_ec</phrase><phrase
role="special">()</phrase></code>. But since a given application is unlikely
to need both, let&#8217;s code <code><phrase role="identifier">read</phrase><phrase
role="special">()</phrase></code> from scratch, leveraging <link linkend="promise_set_exception"><code>promise::set_exception()</code></link>:
</para>
<para>
<programlisting><phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">string</phrase> <phrase role="identifier">read</phrase><phrase role="special">(</phrase> <phrase role="identifier">AsyncAPI</phrase> <phrase role="special">&amp;</phrase> <phrase role="identifier">api</phrase><phrase role="special">)</phrase> <phrase role="special">{</phrase>
<phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">fibers</phrase><phrase role="special">::</phrase><phrase role="identifier">promise</phrase><phrase role="special">&lt;</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">string</phrase> <phrase role="special">&gt;</phrase> <phrase role="identifier">promise</phrase><phrase role="special">;</phrase>
<phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">fibers</phrase><phrase role="special">::</phrase><phrase role="identifier">future</phrase><phrase role="special">&lt;</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">string</phrase> <phrase role="special">&gt;</phrase> <phrase role="identifier">future</phrase><phrase role="special">(</phrase> <phrase role="identifier">promise</phrase><phrase role="special">.</phrase><phrase role="identifier">get_future</phrase><phrase role="special">()</phrase> <phrase role="special">);</phrase>
<phrase role="comment">// Both 'promise' and 'future' will survive until our lambda has been</phrase>
<phrase role="comment">// called.</phrase>
<phrase role="preprocessor">#if</phrase> <phrase role="special">!</phrase> <phrase role="identifier">defined</phrase><phrase role="special">(</phrase><phrase role="identifier">BOOST_NO_CXX14_INITIALIZED_LAMBDA_CAPTURES</phrase><phrase role="special">)</phrase>
<phrase role="identifier">api</phrase><phrase role="special">.</phrase><phrase role="identifier">init_read</phrase><phrase role="special">([&amp;</phrase><phrase role="identifier">promise</phrase><phrase role="special">](</phrase> <phrase role="identifier">AsyncAPI</phrase><phrase role="special">::</phrase><phrase role="identifier">errorcode</phrase> <phrase role="identifier">ec</phrase><phrase role="special">,</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">string</phrase> <phrase role="keyword">const</phrase><phrase role="special">&amp;</phrase> <phrase role="identifier">data</phrase><phrase role="special">)</phrase> <phrase role="keyword">mutable</phrase> <phrase role="special">{</phrase>
<phrase role="keyword">if</phrase> <phrase role="special">(</phrase> <phrase role="special">!</phrase> <phrase role="identifier">ec</phrase><phrase role="special">)</phrase> <phrase role="special">{</phrase>
<phrase role="identifier">promise</phrase><phrase role="special">.</phrase><phrase role="identifier">set_value</phrase><phrase role="special">(</phrase> <phrase role="identifier">data</phrase><phrase role="special">);</phrase>
<phrase role="special">}</phrase> <phrase role="keyword">else</phrase> <phrase role="special">{</phrase>
<phrase role="identifier">promise</phrase><phrase role="special">.</phrase><phrase role="identifier">set_exception</phrase><phrase role="special">(</phrase>
<phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">make_exception_ptr</phrase><phrase role="special">(</phrase>
<phrase role="identifier">make_exception</phrase><phrase role="special">(</phrase><phrase role="string">&quot;read&quot;</phrase><phrase role="special">,</phrase> <phrase role="identifier">ec</phrase><phrase role="special">)</phrase> <phrase role="special">)</phrase> <phrase role="special">);</phrase>
<phrase role="special">}</phrase>
<phrase role="special">});</phrase>
<phrase role="preprocessor">#else</phrase> <phrase role="comment">// defined(BOOST_NO_CXX14_INITIALIZED_LAMBDA_CAPTURES)</phrase>
<phrase role="identifier">api</phrase><phrase role="special">.</phrase><phrase role="identifier">init_read</phrase><phrase role="special">(</phrase>
<phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">bind</phrase><phrase role="special">([](</phrase> <phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">fibers</phrase><phrase role="special">::</phrase><phrase role="identifier">promise</phrase><phrase role="special">&lt;</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">string</phrase> <phrase role="special">&gt;</phrase> <phrase role="special">&amp;</phrase> <phrase role="identifier">promise</phrase><phrase role="special">,</phrase>
<phrase role="identifier">AsyncAPI</phrase><phrase role="special">::</phrase><phrase role="identifier">errorcode</phrase> <phrase role="identifier">ec</phrase><phrase role="special">,</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">string</phrase> <phrase role="keyword">const</phrase><phrase role="special">&amp;</phrase> <phrase role="identifier">data</phrase><phrase role="special">)</phrase> <phrase role="keyword">mutable</phrase> <phrase role="special">{</phrase>
<phrase role="keyword">if</phrase> <phrase role="special">(</phrase> <phrase role="special">!</phrase> <phrase role="identifier">ec</phrase><phrase role="special">)</phrase> <phrase role="special">{</phrase>
<phrase role="identifier">promise</phrase><phrase role="special">.</phrase><phrase role="identifier">set_value</phrase><phrase role="special">(</phrase> <phrase role="identifier">data</phrase><phrase role="special">);</phrase>
<phrase role="special">}</phrase> <phrase role="keyword">else</phrase> <phrase role="special">{</phrase>
<phrase role="identifier">promise</phrase><phrase role="special">.</phrase><phrase role="identifier">set_exception</phrase><phrase role="special">(</phrase>
<phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">make_exception_ptr</phrase><phrase role="special">(</phrase>
<phrase role="identifier">make_exception</phrase><phrase role="special">(</phrase><phrase role="string">&quot;read&quot;</phrase><phrase role="special">,</phrase> <phrase role="identifier">ec</phrase><phrase role="special">)</phrase> <phrase role="special">)</phrase> <phrase role="special">);</phrase>
<phrase role="special">}</phrase>
<phrase role="special">},</phrase>
<phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">move</phrase><phrase role="special">(</phrase> <phrase role="identifier">promise</phrase><phrase role="special">),</phrase>
<phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">placeholders</phrase><phrase role="special">::</phrase><phrase role="identifier">_1</phrase><phrase role="special">,</phrase>
<phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">placeholders</phrase><phrase role="special">::</phrase><phrase role="identifier">_2</phrase><phrase role="special">)</phrase> <phrase role="special">);</phrase>
<phrase role="preprocessor">#endif</phrase> <phrase role="comment">// BOOST_NO_CXX14_INITIALIZED_LAMBDA_CAPTURES</phrase>
<phrase role="keyword">return</phrase> <phrase role="identifier">future</phrase><phrase role="special">.</phrase><phrase role="identifier">get</phrase><phrase role="special">();</phrase>
<phrase role="special">}</phrase>
</programlisting>
</para>
<para>
<link linkend="future_get"><code>future::get()</code></link> will do the right thing, either returning <code><phrase
role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">string</phrase></code>
or throwing an exception.
</para>
</section>
<section id="fiber.callbacks.success_error_virtual_methods">
<title><link linkend="fiber.callbacks.success_error_virtual_methods">Success/Error
Virtual Methods</link></title>
<para>
One classic approach to completion notification is to define an abstract
base class with <code><phrase role="identifier">success</phrase><phrase role="special">()</phrase></code>
and <code><phrase role="identifier">error</phrase><phrase role="special">()</phrase></code>
methods. Code wishing to perform async I/O must derive a subclass, override
each of these methods and pass the async operation a pointer to a subclass
instance. The abstract base class might look like this:
</para>
<para>
<programlisting><phrase role="comment">// every async operation receives a subclass instance of this abstract base</phrase>
<phrase role="comment">// class through which to communicate its result</phrase>
<phrase role="keyword">struct</phrase> <phrase role="identifier">Response</phrase> <phrase role="special">{</phrase>
<phrase role="keyword">typedef</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">shared_ptr</phrase><phrase role="special">&lt;</phrase> <phrase role="identifier">Response</phrase> <phrase role="special">&gt;</phrase> <phrase role="identifier">ptr</phrase><phrase role="special">;</phrase>
<phrase role="comment">// called if the operation succeeds</phrase>
<phrase role="keyword">virtual</phrase> <phrase role="keyword">void</phrase> <phrase role="identifier">success</phrase><phrase role="special">(</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">string</phrase> <phrase role="keyword">const</phrase><phrase role="special">&amp;</phrase> <phrase role="identifier">data</phrase><phrase role="special">)</phrase> <phrase role="special">=</phrase> <phrase role="number">0</phrase><phrase role="special">;</phrase>
<phrase role="comment">// called if the operation fails</phrase>
<phrase role="keyword">virtual</phrase> <phrase role="keyword">void</phrase> <phrase role="identifier">error</phrase><phrase role="special">(</phrase> <phrase role="identifier">AsyncAPIBase</phrase><phrase role="special">::</phrase><phrase role="identifier">errorcode</phrase> <phrase role="identifier">ec</phrase><phrase role="special">)</phrase> <phrase role="special">=</phrase> <phrase role="number">0</phrase><phrase role="special">;</phrase>
<phrase role="special">};</phrase>
</programlisting>
</para>
<para>
Now the <code><phrase role="identifier">AsyncAPI</phrase></code> operation
might look more like this:
</para>
<para>
<programlisting><phrase role="comment">// derive Response subclass, instantiate, pass Response::ptr</phrase>
<phrase role="keyword">void</phrase> <phrase role="identifier">init_read</phrase><phrase role="special">(</phrase> <phrase role="identifier">Response</phrase><phrase role="special">::</phrase><phrase role="identifier">ptr</phrase><phrase role="special">);</phrase>
</programlisting>
</para>
<para>
We can address this by writing a one-size-fits-all <code><phrase role="identifier">PromiseResponse</phrase></code>:
</para>
<para>
<programlisting><phrase role="keyword">class</phrase> <phrase role="identifier">PromiseResponse</phrase><phrase role="special">:</phrase> <phrase role="keyword">public</phrase> <phrase role="identifier">Response</phrase> <phrase role="special">{</phrase>
<phrase role="keyword">public</phrase><phrase role="special">:</phrase>
<phrase role="comment">// called if the operation succeeds</phrase>
<phrase role="keyword">virtual</phrase> <phrase role="keyword">void</phrase> <phrase role="identifier">success</phrase><phrase role="special">(</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">string</phrase> <phrase role="keyword">const</phrase><phrase role="special">&amp;</phrase> <phrase role="identifier">data</phrase><phrase role="special">)</phrase> <phrase role="special">{</phrase>
<phrase role="identifier">promise_</phrase><phrase role="special">.</phrase><phrase role="identifier">set_value</phrase><phrase role="special">(</phrase> <phrase role="identifier">data</phrase><phrase role="special">);</phrase>
<phrase role="special">}</phrase>
<phrase role="comment">// called if the operation fails</phrase>
<phrase role="keyword">virtual</phrase> <phrase role="keyword">void</phrase> <phrase role="identifier">error</phrase><phrase role="special">(</phrase> <phrase role="identifier">AsyncAPIBase</phrase><phrase role="special">::</phrase><phrase role="identifier">errorcode</phrase> <phrase role="identifier">ec</phrase><phrase role="special">)</phrase> <phrase role="special">{</phrase>
<phrase role="identifier">promise_</phrase><phrase role="special">.</phrase><phrase role="identifier">set_exception</phrase><phrase role="special">(</phrase>
<phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">make_exception_ptr</phrase><phrase role="special">(</phrase>
<phrase role="identifier">make_exception</phrase><phrase role="special">(</phrase><phrase role="string">&quot;read&quot;</phrase><phrase role="special">,</phrase> <phrase role="identifier">ec</phrase><phrase role="special">)</phrase> <phrase role="special">)</phrase> <phrase role="special">);</phrase>
<phrase role="special">}</phrase>
<phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">fibers</phrase><phrase role="special">::</phrase><phrase role="identifier">future</phrase><phrase role="special">&lt;</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">string</phrase> <phrase role="special">&gt;</phrase> <phrase role="identifier">get_future</phrase><phrase role="special">()</phrase> <phrase role="special">{</phrase>
<phrase role="keyword">return</phrase> <phrase role="identifier">promise_</phrase><phrase role="special">.</phrase><phrase role="identifier">get_future</phrase><phrase role="special">();</phrase>
<phrase role="special">}</phrase>
<phrase role="keyword">private</phrase><phrase role="special">:</phrase>
<phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">fibers</phrase><phrase role="special">::</phrase><phrase role="identifier">promise</phrase><phrase role="special">&lt;</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">string</phrase> <phrase role="special">&gt;</phrase> <phrase role="identifier">promise_</phrase><phrase role="special">;</phrase>
<phrase role="special">};</phrase>
</programlisting>
</para>
<para>
Now we can simply obtain the <code><phrase role="identifier">future</phrase><phrase
role="special">&lt;&gt;</phrase></code> from that <code><phrase role="identifier">PromiseResponse</phrase></code>
and wait on its <code><phrase role="identifier">get</phrase><phrase role="special">()</phrase></code>:
</para>
<para>
<programlisting><phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">string</phrase> <phrase role="identifier">read</phrase><phrase role="special">(</phrase> <phrase role="identifier">AsyncAPI</phrase> <phrase role="special">&amp;</phrase> <phrase role="identifier">api</phrase><phrase role="special">)</phrase> <phrase role="special">{</phrase>
<phrase role="comment">// Because init_read() requires a shared_ptr, we must allocate our</phrase>
<phrase role="comment">// ResponsePromise on the heap, even though we know its lifespan.</phrase>
<phrase role="keyword">auto</phrase> <phrase role="identifier">promisep</phrase><phrase role="special">(</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">make_shared</phrase><phrase role="special">&lt;</phrase> <phrase role="identifier">PromiseResponse</phrase> <phrase role="special">&gt;()</phrase> <phrase role="special">);</phrase>
<phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">fibers</phrase><phrase role="special">::</phrase><phrase role="identifier">future</phrase><phrase role="special">&lt;</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">string</phrase> <phrase role="special">&gt;</phrase> <phrase role="identifier">future</phrase><phrase role="special">(</phrase> <phrase role="identifier">promisep</phrase><phrase role="special">-&gt;</phrase><phrase role="identifier">get_future</phrase><phrase role="special">()</phrase> <phrase role="special">);</phrase>
<phrase role="comment">// Both 'promisep' and 'future' will survive until our lambda has been</phrase>
<phrase role="comment">// called.</phrase>
<phrase role="identifier">api</phrase><phrase role="special">.</phrase><phrase role="identifier">init_read</phrase><phrase role="special">(</phrase> <phrase role="identifier">promisep</phrase><phrase role="special">);</phrase>
<phrase role="keyword">return</phrase> <phrase role="identifier">future</phrase><phrase role="special">.</phrase><phrase role="identifier">get</phrase><phrase role="special">();</phrase>
<phrase role="special">}</phrase>
</programlisting>
</para>
<para>
The source code above is found in <ulink url="../../examples/adapt_callbacks.cpp">adapt_callbacks.cpp</ulink>
and <ulink url="../../examples/adapt_method_calls.cpp">adapt_method_calls.cpp</ulink>.
</para>
</section>
<section id="fiber.callbacks.then_there_s____boost_asio__">
<title><anchor id="callbacks_asio"/><link linkend="fiber.callbacks.then_there_s____boost_asio__">Then
There&#8217;s <ulink url="http://www.boost.org/doc/libs/release/libs/asio/index.html">Boost.Asio</ulink></link></title>
<para>
Since the simplest form of Boost.Asio asynchronous operation completion token
is a callback function, we could apply the same tactics for Asio as for our
hypothetical <code><phrase role="identifier">AsyncAPI</phrase></code> asynchronous
operations.
</para>
<para>
Fortunately we need not. Boost.Asio incorporates a mechanism<footnote id="fiber.callbacks.then_there_s____boost_asio__.f0">
<para>
This mechanism has been proposed as a conventional way to allow the caller
of an arbitrary async function to specify completion handling: <ulink url="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2014/n4045.pdf">N4045</ulink>.
</para>
</footnote> by which the caller can customize the notification behavior of
any async operation. Therefore we can construct a <emphasis>completion token</emphasis>
which, when passed to a <ulink url="http://www.boost.org/doc/libs/release/libs/asio/index.html">Boost.Asio</ulink>
async operation, requests blocking for the calling fiber.
</para>
<para>
A typical Asio async function might look something like this:<footnote id="fiber.callbacks.then_there_s____boost_asio__.f1">
<para>
per <ulink url="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2014/n4045.pdf">N4045</ulink>
</para>
</footnote>
</para>
<programlisting><phrase role="keyword">template</phrase> <phrase role="special">&lt;</phrase> <phrase role="special">...,</phrase> <phrase role="keyword">class</phrase> <phrase role="identifier">CompletionToken</phrase> <phrase role="special">&gt;</phrase>
<emphasis>deduced_return_type</emphasis>
<phrase role="identifier">async_something</phrase><phrase role="special">(</phrase> <phrase role="special">...</phrase> <phrase role="special">,</phrase> <phrase role="identifier">CompletionToken</phrase><phrase role="special">&amp;&amp;</phrase> <phrase role="identifier">token</phrase><phrase role="special">)</phrase>
<phrase role="special">{</phrase>
<phrase role="comment">// construct handler_type instance from CompletionToken</phrase>
<phrase role="identifier">handler_type</phrase><phrase role="special">&lt;</phrase><phrase role="identifier">CompletionToken</phrase><phrase role="special">,</phrase> <phrase role="special">...&gt;::</phrase><phrase role="identifier">type</phrase> <emphasis role="bold"><!--quickbook-escape-prefix--><code><!--quickbook-escape-postfix-->handler(token)<!--quickbook-escape-prefix--></code><!--quickbook-escape-postfix--></emphasis><phrase role="special">;</phrase>
<phrase role="comment">// construct async_result instance from handler_type</phrase>
<phrase role="identifier">async_result</phrase><phrase role="special">&lt;</phrase><phrase role="keyword">decltype</phrase><phrase role="special">(</phrase><phrase role="identifier">handler</phrase><phrase role="special">)&gt;</phrase> <emphasis role="bold"><!--quickbook-escape-prefix--><code><!--quickbook-escape-postfix-->result(handler)<!--quickbook-escape-prefix--></code><!--quickbook-escape-postfix--></emphasis><phrase role="special">;</phrase>
<phrase role="comment">// ... arrange to call handler on completion ...</phrase>
<phrase role="comment">// ... initiate actual I/O operation ...</phrase>
<phrase role="keyword">return</phrase> <emphasis role="bold"><!--quickbook-escape-prefix--><code><!--quickbook-escape-postfix-->result.get()<!--quickbook-escape-prefix--></code><!--quickbook-escape-postfix--></emphasis><phrase role="special">;</phrase>
<phrase role="special">}</phrase>
</programlisting>
<para>
We will engage that mechanism, which is based on specializing Asio&#8217;s <code><phrase
role="identifier">handler_type</phrase><phrase role="special">&lt;&gt;</phrase></code>
template for the <code><phrase role="identifier">CompletionToken</phrase></code>
type and the signature of the specific callback. The remainder of this discussion
will refer back to <code><phrase role="identifier">async_something</phrase><phrase
role="special">()</phrase></code> as the Asio async function under consideration.
</para>
<para>
The implementation described below uses lower-level facilities than <code><phrase
role="identifier">promise</phrase></code> and <code><phrase role="identifier">future</phrase></code>
because the <code><phrase role="identifier">promise</phrase></code> mechanism
interacts badly with <ulink url="http://www.boost.org/doc/libs/release/doc/html/boost_asio/reference/io_service/stop.html"><code><phrase
role="identifier">io_service</phrase><phrase role="special">::</phrase><phrase
role="identifier">stop</phrase><phrase role="special">()</phrase></code></ulink>.
It produces <code><phrase role="identifier">broken_promise</phrase></code>
exceptions.
</para>
<para>
<code><phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase
role="identifier">fibers</phrase><phrase role="special">::</phrase><phrase
role="identifier">asio</phrase><phrase role="special">::</phrase><phrase
role="identifier">yield</phrase></code> is a completion token of this kind.
<code><phrase role="identifier">yield</phrase></code> is an instance of
<code><phrase role="identifier">yield_t</phrase></code>:
</para>
<para>
<programlisting><phrase role="keyword">class</phrase> <phrase role="identifier">yield_t</phrase> <phrase role="special">{</phrase>
<phrase role="keyword">public</phrase><phrase role="special">:</phrase>
<phrase role="identifier">yield_t</phrase><phrase role="special">()</phrase> <phrase role="special">=</phrase> <phrase role="keyword">default</phrase><phrase role="special">;</phrase>
<phrase role="comment">/**
* @code
* static yield_t yield;
* boost::system::error_code myec;
* func(yield[myec]);
* @endcode
* @c yield[myec] returns an instance of @c yield_t whose @c ec_ points
* to @c myec. The expression @c yield[myec] &quot;binds&quot; @c myec to that
* (anonymous) @c yield_t instance, instructing @c func() to store any
* @c error_code it might produce into @c myec rather than throwing @c
* boost::system::system_error.
*/</phrase>
<phrase role="identifier">yield_t</phrase> <phrase role="keyword">operator</phrase><phrase role="special">[](</phrase> <phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">system</phrase><phrase role="special">::</phrase><phrase role="identifier">error_code</phrase> <phrase role="special">&amp;</phrase> <phrase role="identifier">ec</phrase><phrase role="special">)</phrase> <phrase role="keyword">const</phrase> <phrase role="special">{</phrase>
<phrase role="identifier">yield_t</phrase> <phrase role="identifier">tmp</phrase><phrase role="special">;</phrase>
<phrase role="identifier">tmp</phrase><phrase role="special">.</phrase><phrase role="identifier">ec_</phrase> <phrase role="special">=</phrase> <phrase role="special">&amp;</phrase> <phrase role="identifier">ec</phrase><phrase role="special">;</phrase>
<phrase role="keyword">return</phrase> <phrase role="identifier">tmp</phrase><phrase role="special">;</phrase>
<phrase role="special">}</phrase>
<phrase role="comment">//private:</phrase>
<phrase role="comment">// ptr to bound error_code instance if any</phrase>
<phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">system</phrase><phrase role="special">::</phrase><phrase role="identifier">error_code</phrase> <phrase role="special">*</phrase> <phrase role="identifier">ec_</phrase><phrase role="special">{</phrase> <phrase role="keyword">nullptr</phrase> <phrase role="special">};</phrase>
<phrase role="special">};</phrase>
</programlisting>
</para>
<para>
<code><phrase role="identifier">yield_t</phrase></code> is in fact only a
placeholder, a way to trigger Boost.Asio customization. It can bind a <ulink
url="http://www.boost.org/doc/libs/release/libs/system/doc/reference.html#Class-error_code"><code><phrase
role="identifier">boost</phrase><phrase role="special">::</phrase><phrase
role="identifier">system</phrase><phrase role="special">::</phrase><phrase
role="identifier">error_code</phrase></code></ulink> for use by the actual
handler.
</para>
<para>
<code><phrase role="identifier">yield</phrase></code> is declared as:
</para>
<para>
<programlisting><phrase role="comment">// canonical instance</phrase>
<phrase role="keyword">thread_local</phrase> <phrase role="identifier">yield_t</phrase> <phrase role="identifier">yield</phrase><phrase role="special">{};</phrase>
</programlisting>
</para>
<para>
Asio customization is engaged by specializing <ulink url="http://www.boost.org/doc/libs/release/doc/html/boost_asio/reference/handler_type.html"><code><phrase
role="identifier">boost</phrase><phrase role="special">::</phrase><phrase
role="identifier">asio</phrase><phrase role="special">::</phrase><phrase
role="identifier">handler_type</phrase><phrase role="special">&lt;&gt;</phrase></code></ulink>
for <code><phrase role="identifier">yield_t</phrase></code>:
</para>
<para>
<programlisting><phrase role="comment">// Handler type specialisation for fibers::asio::yield.</phrase>
<phrase role="comment">// When 'yield' is passed as a completion handler which accepts only</phrase>
<phrase role="comment">// error_code, use yield_handler&lt;void&gt;. yield_handler will take care of the</phrase>
<phrase role="comment">// error_code one way or another.</phrase>
<phrase role="keyword">template</phrase><phrase role="special">&lt;</phrase> <phrase role="keyword">typename</phrase> <phrase role="identifier">ReturnType</phrase> <phrase role="special">&gt;</phrase>
<phrase role="keyword">struct</phrase> <phrase role="identifier">handler_type</phrase><phrase role="special">&lt;</phrase> <phrase role="identifier">fibers</phrase><phrase role="special">::</phrase><phrase role="identifier">asio</phrase><phrase role="special">::</phrase><phrase role="identifier">yield_t</phrase><phrase role="special">,</phrase> <phrase role="identifier">ReturnType</phrase><phrase role="special">(</phrase> <phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">system</phrase><phrase role="special">::</phrase><phrase role="identifier">error_code</phrase><phrase role="special">)</phrase> <phrase role="special">&gt;</phrase>
<phrase role="special">{</phrase> <phrase role="keyword">typedef</phrase> <phrase role="identifier">fibers</phrase><phrase role="special">::</phrase><phrase role="identifier">asio</phrase><phrase role="special">::</phrase><phrase role="identifier">detail</phrase><phrase role="special">::</phrase><phrase role="identifier">yield_handler</phrase><phrase role="special">&lt;</phrase> <phrase role="keyword">void</phrase> <phrase role="special">&gt;</phrase> <phrase role="identifier">type</phrase><phrase role="special">;</phrase> <phrase role="special">};</phrase>
</programlisting>
</para>
<para>
(There are actually four different specializations in <ulink url="../../examples/asio/detail/yield.hpp">detail/yield.hpp</ulink>,
one for each of the four Asio async callback signatures we expect.)
</para>
<para>
The above directs Asio to use <code><phrase role="identifier">yield_handler</phrase></code>
as the actual handler for an async operation to which <code><phrase role="identifier">yield</phrase></code>
is passed. There&#8217;s a generic <code><phrase role="identifier">yield_handler</phrase><phrase
role="special">&lt;</phrase><phrase role="identifier">T</phrase><phrase role="special">&gt;</phrase></code>
implementation and a <code><phrase role="identifier">yield_handler</phrase><phrase
role="special">&lt;</phrase><phrase role="keyword">void</phrase><phrase role="special">&gt;</phrase></code>
specialization. Let&#8217;s start with the <code><phrase role="special">&lt;</phrase><phrase
role="keyword">void</phrase><phrase role="special">&gt;</phrase></code> specialization:
</para>
<para>
<programlisting><phrase role="comment">// yield_handler&lt;void&gt; is like yield_handler&lt;T&gt; without value_. In fact it's</phrase>
<phrase role="comment">// just like yield_handler_base.</phrase>
<phrase role="keyword">template</phrase><phrase role="special">&lt;&gt;</phrase>
<phrase role="keyword">class</phrase> <phrase role="identifier">yield_handler</phrase><phrase role="special">&lt;</phrase> <phrase role="keyword">void</phrase> <phrase role="special">&gt;:</phrase> <phrase role="keyword">public</phrase> <phrase role="identifier">yield_handler_base</phrase> <phrase role="special">{</phrase>
<phrase role="keyword">public</phrase><phrase role="special">:</phrase>
<phrase role="keyword">explicit</phrase> <phrase role="identifier">yield_handler</phrase><phrase role="special">(</phrase> <phrase role="identifier">yield_t</phrase> <phrase role="keyword">const</phrase><phrase role="special">&amp;</phrase> <phrase role="identifier">y</phrase><phrase role="special">)</phrase> <phrase role="special">:</phrase>
<phrase role="identifier">yield_handler_base</phrase><phrase role="special">{</phrase> <phrase role="identifier">y</phrase> <phrase role="special">}</phrase> <phrase role="special">{</phrase>
<phrase role="special">}</phrase>
<phrase role="comment">// nullary completion callback</phrase>
<phrase role="keyword">void</phrase> <phrase role="keyword">operator</phrase><phrase role="special">()()</phrase> <phrase role="special">{</phrase>
<phrase role="special">(</phrase> <phrase role="special">*</phrase> <phrase role="keyword">this</phrase><phrase role="special">)(</phrase> <phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">system</phrase><phrase role="special">::</phrase><phrase role="identifier">error_code</phrase><phrase role="special">()</phrase> <phrase role="special">);</phrase>
<phrase role="special">}</phrase>
<phrase role="comment">// inherit operator()(error_code) overload from base class</phrase>
<phrase role="keyword">using</phrase> <phrase role="identifier">yield_handler_base</phrase><phrase role="special">::</phrase><phrase role="keyword">operator</phrase><phrase role="special">();</phrase>
<phrase role="special">};</phrase>
</programlisting>
</para>
<para>
<code><phrase role="identifier">async_something</phrase><phrase role="special">()</phrase></code>,
having consulted the <code><phrase role="identifier">handler_type</phrase><phrase
role="special">&lt;&gt;</phrase></code> traits specialization, instantiates
a <code><phrase role="identifier">yield_handler</phrase><phrase role="special">&lt;</phrase><phrase
role="keyword">void</phrase><phrase role="special">&gt;</phrase></code> to
be passed as the actual callback for the async operation. <code><phrase role="identifier">yield_handler</phrase></code>&#8217;s
constructor accepts the <code><phrase role="identifier">yield_t</phrase></code>
instance (the <code><phrase role="identifier">yield</phrase></code> object
passed to the async function) and passes it along to <code><phrase role="identifier">yield_handler_base</phrase></code>:
</para>
<para>
<programlisting><phrase role="comment">// This class encapsulates common elements between yield_handler&lt;T&gt; (capturing</phrase>
<phrase role="comment">// a value to return from asio async function) and yield_handler&lt;void&gt; (no</phrase>
<phrase role="comment">// such value). See yield_handler&lt;T&gt; and its &lt;void&gt; specialization below. Both</phrase>
<phrase role="comment">// yield_handler&lt;T&gt; and yield_handler&lt;void&gt; are passed by value through</phrase>
<phrase role="comment">// various layers of asio functions. In other words, they're potentially</phrase>
<phrase role="comment">// copied multiple times. So key data such as the yield_completion instance</phrase>
<phrase role="comment">// must be stored in our async_result&lt;yield_handler&lt;&gt;&gt; specialization, which</phrase>
<phrase role="comment">// should be instantiated only once.</phrase>
<phrase role="keyword">class</phrase> <phrase role="identifier">yield_handler_base</phrase> <phrase role="special">{</phrase>
<phrase role="keyword">public</phrase><phrase role="special">:</phrase>
<phrase role="identifier">yield_handler_base</phrase><phrase role="special">(</phrase> <phrase role="identifier">yield_t</phrase> <phrase role="keyword">const</phrase><phrase role="special">&amp;</phrase> <phrase role="identifier">y</phrase><phrase role="special">)</phrase> <phrase role="special">:</phrase>
<phrase role="comment">// capture the context* associated with the running fiber</phrase>
<phrase role="identifier">ctx_</phrase><phrase role="special">{</phrase> <phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">fibers</phrase><phrase role="special">::</phrase><phrase role="identifier">context</phrase><phrase role="special">::</phrase><phrase role="identifier">active</phrase><phrase role="special">()</phrase> <phrase role="special">},</phrase>
<phrase role="comment">// capture the passed yield_t</phrase>
<phrase role="identifier">yt_</phrase><phrase role="special">(</phrase> <phrase role="identifier">y</phrase> <phrase role="special">)</phrase> <phrase role="special">{</phrase>
<phrase role="special">}</phrase>
<phrase role="comment">// completion callback passing only (error_code)</phrase>
<phrase role="keyword">void</phrase> <phrase role="keyword">operator</phrase><phrase role="special">()(</phrase> <phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">system</phrase><phrase role="special">::</phrase><phrase role="identifier">error_code</phrase> <phrase role="keyword">const</phrase><phrase role="special">&amp;</phrase> <phrase role="identifier">ec</phrase><phrase role="special">)</phrase> <phrase role="special">{</phrase>
<phrase role="identifier">BOOST_ASSERT_MSG</phrase><phrase role="special">(</phrase> <phrase role="identifier">ycomp_</phrase><phrase role="special">,</phrase>
<phrase role="string">&quot;Must inject yield_completion* &quot;</phrase>
<phrase role="string">&quot;before calling yield_handler_base::operator()()&quot;</phrase><phrase role="special">);</phrase>
<phrase role="identifier">BOOST_ASSERT_MSG</phrase><phrase role="special">(</phrase> <phrase role="identifier">yt_</phrase><phrase role="special">.</phrase><phrase role="identifier">ec_</phrase><phrase role="special">,</phrase>
<phrase role="string">&quot;Must inject boost::system::error_code* &quot;</phrase>
<phrase role="string">&quot;before calling yield_handler_base::operator()()&quot;</phrase><phrase role="special">);</phrase>
<phrase role="comment">// If originating fiber is busy testing state_ flag, wait until it</phrase>
<phrase role="comment">// has observed (completed != state_).</phrase>
<phrase role="identifier">yield_completion</phrase><phrase role="special">::</phrase><phrase role="identifier">lock_t</phrase> <phrase role="identifier">lk</phrase><phrase role="special">{</phrase> <phrase role="identifier">ycomp_</phrase><phrase role="special">-&gt;</phrase><phrase role="identifier">mtx_</phrase> <phrase role="special">};</phrase>
<phrase role="identifier">yield_completion</phrase><phrase role="special">::</phrase><phrase role="identifier">state_t</phrase> <phrase role="identifier">state</phrase> <phrase role="special">=</phrase> <phrase role="identifier">ycomp_</phrase><phrase role="special">-&gt;</phrase><phrase role="identifier">state_</phrase><phrase role="special">;</phrase>
<phrase role="comment">// Notify a subsequent yield_completion::wait() call that it need not</phrase>
<phrase role="comment">// suspend.</phrase>
<phrase role="identifier">ycomp_</phrase><phrase role="special">-&gt;</phrase><phrase role="identifier">state_</phrase> <phrase role="special">=</phrase> <phrase role="identifier">yield_completion</phrase><phrase role="special">::</phrase><phrase role="identifier">complete</phrase><phrase role="special">;</phrase>
<phrase role="comment">// set the error_code bound by yield_t</phrase>
<phrase role="special">*</phrase> <phrase role="identifier">yt_</phrase><phrase role="special">.</phrase><phrase role="identifier">ec_</phrase> <phrase role="special">=</phrase> <phrase role="identifier">ec</phrase><phrase role="special">;</phrase>
<phrase role="comment">// unlock the lock that protects state_</phrase>
<phrase role="identifier">lk</phrase><phrase role="special">.</phrase><phrase role="identifier">unlock</phrase><phrase role="special">();</phrase>
<phrase role="comment">// If ctx_ is still active, e.g. because the async operation</phrase>
<phrase role="comment">// immediately called its callback (this method!) before the asio</phrase>
<phrase role="comment">// async function called async_result_base::get(), we must not set it</phrase>
<phrase role="comment">// ready.</phrase>
<phrase role="keyword">if</phrase> <phrase role="special">(</phrase> <phrase role="identifier">yield_completion</phrase><phrase role="special">::</phrase><phrase role="identifier">waiting</phrase> <phrase role="special">==</phrase> <phrase role="identifier">state</phrase><phrase role="special">)</phrase> <phrase role="special">{</phrase>
<phrase role="comment">// wake the fiber</phrase>
<phrase role="identifier">fibers</phrase><phrase role="special">::</phrase><phrase role="identifier">context</phrase><phrase role="special">::</phrase><phrase role="identifier">active</phrase><phrase role="special">()-&gt;</phrase><phrase role="identifier">schedule</phrase><phrase role="special">(</phrase> <phrase role="identifier">ctx_</phrase><phrase role="special">);</phrase>
<phrase role="special">}</phrase>
<phrase role="special">}</phrase>
<phrase role="comment">//private:</phrase>
<phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">fibers</phrase><phrase role="special">::</phrase><phrase role="identifier">context</phrase> <phrase role="special">*</phrase> <phrase role="identifier">ctx_</phrase><phrase role="special">;</phrase>
<phrase role="identifier">yield_t</phrase> <phrase role="identifier">yt_</phrase><phrase role="special">;</phrase>
<phrase role="comment">// We depend on this pointer to yield_completion, which will be injected</phrase>
<phrase role="comment">// by async_result.</phrase>
<phrase role="identifier">yield_completion</phrase><phrase role="special">::</phrase><phrase role="identifier">ptr_t</phrase> <phrase role="identifier">ycomp_</phrase><phrase role="special">{};</phrase>
<phrase role="special">};</phrase>
</programlisting>
</para>
<para>
<code><phrase role="identifier">yield_handler_base</phrase></code> stores
a copy of the <code><phrase role="identifier">yield_t</phrase></code> instance
&mdash; which, as shown above, contains only an <code><phrase role="identifier">error_code</phrase><phrase
role="special">*</phrase></code>. It also captures the <link linkend="class_context"><code>context</code></link>*
for the currently-running fiber by calling <link linkend="context_active"><code>context::active()</code></link>.
</para>
<para>
You will notice that <code><phrase role="identifier">yield_handler_base</phrase></code>
has one more data member (<code><phrase role="identifier">ycomp_</phrase></code>)
that is initialized to <code><phrase role="keyword">nullptr</phrase></code>
by its constructor &mdash; though its <code><phrase role="keyword">operator</phrase><phrase
role="special">()()</phrase></code> method relies on <code><phrase role="identifier">ycomp_</phrase></code>
being non-null. More on this in a moment.
</para>
<para>
Having constructed the <code><phrase role="identifier">yield_handler</phrase><phrase
role="special">&lt;</phrase><phrase role="keyword">void</phrase><phrase role="special">&gt;</phrase></code>
instance, <code><phrase role="identifier">async_something</phrase><phrase
role="special">()</phrase></code> goes on to construct an <code><phrase role="identifier">async_result</phrase></code>
specialized for the <code><phrase role="identifier">handler_type</phrase><phrase
role="special">&lt;&gt;::</phrase><phrase role="identifier">type</phrase></code>:
in this case, <code><phrase role="identifier">async_result</phrase><phrase
role="special">&lt;</phrase><phrase role="identifier">yield_handler</phrase><phrase
role="special">&lt;</phrase><phrase role="keyword">void</phrase><phrase role="special">&gt;&gt;</phrase></code>.
It passes the <code><phrase role="identifier">yield_handler</phrase><phrase
role="special">&lt;</phrase><phrase role="keyword">void</phrase><phrase role="special">&gt;</phrase></code>
instance to the new <code><phrase role="identifier">async_result</phrase></code>
instance.
</para>
<para>
<programlisting><phrase role="comment">// Without the need to handle a passed value, our yield_handler&lt;void&gt;</phrase>
<phrase role="comment">// specialization is just like async_result_base.</phrase>
<phrase role="keyword">template</phrase><phrase role="special">&lt;&gt;</phrase>
<phrase role="keyword">class</phrase> <phrase role="identifier">async_result</phrase><phrase role="special">&lt;</phrase> <phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">fibers</phrase><phrase role="special">::</phrase><phrase role="identifier">asio</phrase><phrase role="special">::</phrase><phrase role="identifier">detail</phrase><phrase role="special">::</phrase><phrase role="identifier">yield_handler</phrase><phrase role="special">&lt;</phrase> <phrase role="keyword">void</phrase> <phrase role="special">&gt;</phrase> <phrase role="special">&gt;</phrase> <phrase role="special">:</phrase>
<phrase role="keyword">public</phrase> <phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">fibers</phrase><phrase role="special">::</phrase><phrase role="identifier">asio</phrase><phrase role="special">::</phrase><phrase role="identifier">detail</phrase><phrase role="special">::</phrase><phrase role="identifier">async_result_base</phrase> <phrase role="special">{</phrase>
<phrase role="keyword">public</phrase><phrase role="special">:</phrase>
<phrase role="keyword">typedef</phrase> <phrase role="keyword">void</phrase> <phrase role="identifier">type</phrase><phrase role="special">;</phrase>
<phrase role="keyword">explicit</phrase> <phrase role="identifier">async_result</phrase><phrase role="special">(</phrase> <phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">fibers</phrase><phrase role="special">::</phrase><phrase role="identifier">asio</phrase><phrase role="special">::</phrase><phrase role="identifier">detail</phrase><phrase role="special">::</phrase><phrase role="identifier">yield_handler</phrase><phrase role="special">&lt;</phrase> <phrase role="keyword">void</phrase> <phrase role="special">&gt;</phrase> <phrase role="special">&amp;</phrase> <phrase role="identifier">h</phrase><phrase role="special">):</phrase>
<phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">fibers</phrase><phrase role="special">::</phrase><phrase role="identifier">asio</phrase><phrase role="special">::</phrase><phrase role="identifier">detail</phrase><phrase role="special">::</phrase><phrase role="identifier">async_result_base</phrase><phrase role="special">{</phrase> <phrase role="identifier">h</phrase> <phrase role="special">}</phrase> <phrase role="special">{</phrase>
<phrase role="special">}</phrase>
<phrase role="special">};</phrase>
</programlisting>
</para>
<para>
Naturally that leads us straight to <code><phrase role="identifier">async_result_base</phrase></code>:
</para>
<para>
<programlisting><phrase role="comment">// Factor out commonality between async_result&lt;yield_handler&lt;T&gt;&gt; and</phrase>
<phrase role="comment">// async_result&lt;yield_handler&lt;void&gt;&gt;</phrase>
<phrase role="keyword">class</phrase> <phrase role="identifier">async_result_base</phrase> <phrase role="special">{</phrase>
<phrase role="keyword">public</phrase><phrase role="special">:</phrase>
<phrase role="keyword">explicit</phrase> <phrase role="identifier">async_result_base</phrase><phrase role="special">(</phrase> <phrase role="identifier">yield_handler_base</phrase> <phrase role="special">&amp;</phrase> <phrase role="identifier">h</phrase><phrase role="special">)</phrase> <phrase role="special">:</phrase>
<phrase role="identifier">ycomp_</phrase><phrase role="special">{</phrase> <phrase role="keyword">new</phrase> <phrase role="identifier">yield_completion</phrase><phrase role="special">{}</phrase> <phrase role="special">}</phrase> <phrase role="special">{</phrase>
<phrase role="comment">// Inject ptr to our yield_completion instance into this</phrase>
<phrase role="comment">// yield_handler&lt;&gt;.</phrase>
<phrase role="identifier">h</phrase><phrase role="special">.</phrase><phrase role="identifier">ycomp_</phrase> <phrase role="special">=</phrase> <phrase role="keyword">this</phrase><phrase role="special">-&gt;</phrase><phrase role="identifier">ycomp_</phrase><phrase role="special">;</phrase>
<phrase role="comment">// if yield_t didn't bind an error_code, make yield_handler_base's</phrase>
<phrase role="comment">// error_code* point to an error_code local to this object so</phrase>
<phrase role="comment">// yield_handler_base::operator() can unconditionally store through</phrase>
<phrase role="comment">// its error_code*</phrase>
<phrase role="keyword">if</phrase> <phrase role="special">(</phrase> <phrase role="special">!</phrase> <phrase role="identifier">h</phrase><phrase role="special">.</phrase><phrase role="identifier">yt_</phrase><phrase role="special">.</phrase><phrase role="identifier">ec_</phrase><phrase role="special">)</phrase> <phrase role="special">{</phrase>
<phrase role="identifier">h</phrase><phrase role="special">.</phrase><phrase role="identifier">yt_</phrase><phrase role="special">.</phrase><phrase role="identifier">ec_</phrase> <phrase role="special">=</phrase> <phrase role="special">&amp;</phrase> <phrase role="identifier">ec_</phrase><phrase role="special">;</phrase>
<phrase role="special">}</phrase>
<phrase role="special">}</phrase>
<phrase role="keyword">void</phrase> <phrase role="identifier">get</phrase><phrase role="special">()</phrase> <phrase role="special">{</phrase>
<phrase role="comment">// Unless yield_handler_base::operator() has already been called,</phrase>
<phrase role="comment">// suspend the calling fiber until that call.</phrase>
<phrase role="identifier">ycomp_</phrase><phrase role="special">-&gt;</phrase><phrase role="identifier">wait</phrase><phrase role="special">();</phrase>
<phrase role="comment">// The only way our own ec_ member could have a non-default value is</phrase>
<phrase role="comment">// if our yield_handler did not have a bound error_code AND the</phrase>
<phrase role="comment">// completion callback passed a non-default error_code.</phrase>
<phrase role="keyword">if</phrase> <phrase role="special">(</phrase> <phrase role="identifier">ec_</phrase><phrase role="special">)</phrase> <phrase role="special">{</phrase>
<phrase role="identifier">throw_exception</phrase><phrase role="special">(</phrase> <phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">system</phrase><phrase role="special">::</phrase><phrase role="identifier">system_error</phrase><phrase role="special">{</phrase> <phrase role="identifier">ec_</phrase> <phrase role="special">}</phrase> <phrase role="special">);</phrase>
<phrase role="special">}</phrase>
<phrase role="special">}</phrase>
<phrase role="keyword">private</phrase><phrase role="special">:</phrase>
<phrase role="comment">// If yield_t does not bind an error_code instance, store into here.</phrase>
<phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">system</phrase><phrase role="special">::</phrase><phrase role="identifier">error_code</phrase> <phrase role="identifier">ec_</phrase><phrase role="special">{};</phrase>
<phrase role="identifier">yield_completion</phrase><phrase role="special">::</phrase><phrase role="identifier">ptr_t</phrase> <phrase role="identifier">ycomp_</phrase><phrase role="special">;</phrase>
<phrase role="special">};</phrase>
</programlisting>
</para>
<para>
This is how <code><phrase role="identifier">yield_handler_base</phrase><phrase
role="special">::</phrase><phrase role="identifier">ycomp_</phrase></code>
becomes non-null: <code><phrase role="identifier">async_result_base</phrase></code>&#8217;s
constructor injects a pointer back to its own <code><phrase role="identifier">yield_completion</phrase></code>
member.
</para>
<para>
Recall that the canonical <code><phrase role="identifier">yield_t</phrase></code>
instance <code><phrase role="identifier">yield</phrase></code> initializes
its <code><phrase role="identifier">error_code</phrase><phrase role="special">*</phrase></code>
member <code><phrase role="identifier">ec_</phrase></code> to <code><phrase
role="keyword">nullptr</phrase></code>. If this instance is passed to <code><phrase
role="identifier">async_something</phrase><phrase role="special">()</phrase></code>
(<code><phrase role="identifier">ec_</phrase></code> is still <code><phrase
role="keyword">nullptr</phrase></code>), the copy stored in <code><phrase
role="identifier">yield_handler_base</phrase></code> will likewise have null
<code><phrase role="identifier">ec_</phrase></code>. <code><phrase role="identifier">async_result_base</phrase></code>&#8217;s
constructor sets <code><phrase role="identifier">yield_handler_base</phrase></code>&#8217;s
<code><phrase role="identifier">yield_t</phrase></code>&#8217;s <code><phrase role="identifier">ec_</phrase></code>
member to point to its own <code><phrase role="identifier">error_code</phrase></code>
member.
</para>
<para>
The stage is now set. <code><phrase role="identifier">async_something</phrase><phrase
role="special">()</phrase></code> initiates the actual async operation, arranging
to call its <code><phrase role="identifier">yield_handler</phrase><phrase
role="special">&lt;</phrase><phrase role="keyword">void</phrase><phrase role="special">&gt;</phrase></code>
instance on completion. Let&#8217;s say, for the sake of argument, that the actual
async operation&#8217;s callback has signature <code><phrase role="keyword">void</phrase><phrase
role="special">(</phrase><phrase role="identifier">error_code</phrase><phrase
role="special">)</phrase></code>.
</para>
<para>
But since it&#8217;s an async operation, control returns at once to <code><phrase
role="identifier">async_something</phrase><phrase role="special">()</phrase></code>.
<code><phrase role="identifier">async_something</phrase><phrase role="special">()</phrase></code>
calls <code><phrase role="identifier">async_result</phrase><phrase role="special">&lt;</phrase><phrase
role="identifier">yield_handler</phrase><phrase role="special">&lt;</phrase><phrase
role="keyword">void</phrase><phrase role="special">&gt;&gt;::</phrase><phrase
role="identifier">get</phrase><phrase role="special">()</phrase></code>,
and will return its return value.
</para>
<para>
<code><phrase role="identifier">async_result</phrase><phrase role="special">&lt;</phrase><phrase
role="identifier">yield_handler</phrase><phrase role="special">&lt;</phrase><phrase
role="keyword">void</phrase><phrase role="special">&gt;&gt;::</phrase><phrase
role="identifier">get</phrase><phrase role="special">()</phrase></code> inherits
<code><phrase role="identifier">async_result_base</phrase><phrase role="special">::</phrase><phrase
role="identifier">get</phrase><phrase role="special">()</phrase></code>.
</para>
<para>
<code><phrase role="identifier">async_result_base</phrase><phrase role="special">::</phrase><phrase
role="identifier">get</phrase><phrase role="special">()</phrase></code> immediately
calls <code><phrase role="identifier">yield_completion</phrase><phrase role="special">::</phrase><phrase
role="identifier">wait</phrase><phrase role="special">()</phrase></code>.
</para>
<para>
<programlisting><phrase role="comment">// Bundle a completion bool flag with a spinlock to protect it.</phrase>
<phrase role="keyword">struct</phrase> <phrase role="identifier">yield_completion</phrase> <phrase role="special">{</phrase>
<phrase role="keyword">enum</phrase> <phrase role="identifier">state_t</phrase> <phrase role="special">{</phrase>
<phrase role="identifier">init</phrase><phrase role="special">,</phrase>
<phrase role="identifier">waiting</phrase><phrase role="special">,</phrase>
<phrase role="identifier">complete</phrase>
<phrase role="special">};</phrase>
<phrase role="keyword">typedef</phrase> <phrase role="identifier">fibers</phrase><phrase role="special">::</phrase><phrase role="identifier">detail</phrase><phrase role="special">::</phrase><phrase role="identifier">spinlock</phrase> <phrase role="identifier">mutex_t</phrase><phrase role="special">;</phrase>
<phrase role="keyword">typedef</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">unique_lock</phrase><phrase role="special">&lt;</phrase> <phrase role="identifier">mutex_t</phrase> <phrase role="special">&gt;</phrase> <phrase role="identifier">lock_t</phrase><phrase role="special">;</phrase>
<phrase role="keyword">typedef</phrase> <phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">intrusive_ptr</phrase><phrase role="special">&lt;</phrase> <phrase role="identifier">yield_completion</phrase> <phrase role="special">&gt;</phrase> <phrase role="identifier">ptr_t</phrase><phrase role="special">;</phrase>
<phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">atomic</phrase><phrase role="special">&lt;</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">size_t</phrase> <phrase role="special">&gt;</phrase> <phrase role="identifier">use_count_</phrase><phrase role="special">{</phrase> <phrase role="number">0</phrase> <phrase role="special">};</phrase>
<phrase role="identifier">mutex_t</phrase> <phrase role="identifier">mtx_</phrase><phrase role="special">{};</phrase>
<phrase role="identifier">state_t</phrase> <phrase role="identifier">state_</phrase><phrase role="special">{</phrase> <phrase role="identifier">init</phrase> <phrase role="special">};</phrase>
<phrase role="keyword">void</phrase> <phrase role="identifier">wait</phrase><phrase role="special">()</phrase> <phrase role="special">{</phrase>
<phrase role="comment">// yield_handler_base::operator()() will set state_ `complete` and</phrase>
<phrase role="comment">// attempt to wake a suspended fiber. It would be Bad if that call</phrase>
<phrase role="comment">// happened between our detecting (complete != state_) and suspending.</phrase>
<phrase role="identifier">lock_t</phrase> <phrase role="identifier">lk</phrase><phrase role="special">{</phrase> <phrase role="identifier">mtx_</phrase> <phrase role="special">};</phrase>
<phrase role="comment">// If state_ is already set, we're done here: don't suspend.</phrase>
<phrase role="keyword">if</phrase> <phrase role="special">(</phrase> <phrase role="identifier">complete</phrase> <phrase role="special">!=</phrase> <phrase role="identifier">state_</phrase><phrase role="special">)</phrase> <phrase role="special">{</phrase>
<phrase role="identifier">state_</phrase> <phrase role="special">=</phrase> <phrase role="identifier">waiting</phrase><phrase role="special">;</phrase>
<phrase role="comment">// suspend(unique_lock&lt;spinlock&gt;) unlocks the lock in the act of</phrase>
<phrase role="comment">// resuming another fiber</phrase>
<phrase role="identifier">fibers</phrase><phrase role="special">::</phrase><phrase role="identifier">context</phrase><phrase role="special">::</phrase><phrase role="identifier">active</phrase><phrase role="special">()-&gt;</phrase><phrase role="identifier">suspend</phrase><phrase role="special">(</phrase> <phrase role="identifier">lk</phrase><phrase role="special">);</phrase>
<phrase role="special">}</phrase>
<phrase role="special">}</phrase>
<phrase role="keyword">friend</phrase> <phrase role="keyword">void</phrase> <phrase role="identifier">intrusive_ptr_add_ref</phrase><phrase role="special">(</phrase> <phrase role="identifier">yield_completion</phrase> <phrase role="special">*</phrase> <phrase role="identifier">yc</phrase><phrase role="special">)</phrase> <phrase role="keyword">noexcept</phrase> <phrase role="special">{</phrase>
<phrase role="identifier">BOOST_ASSERT</phrase><phrase role="special">(</phrase> <phrase role="keyword">nullptr</phrase> <phrase role="special">!=</phrase> <phrase role="identifier">yc</phrase><phrase role="special">);</phrase>
<phrase role="identifier">yc</phrase><phrase role="special">-&gt;</phrase><phrase role="identifier">use_count_</phrase><phrase role="special">.</phrase><phrase role="identifier">fetch_add</phrase><phrase role="special">(</phrase> <phrase role="number">1</phrase><phrase role="special">,</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">memory_order_relaxed</phrase><phrase role="special">);</phrase>
<phrase role="special">}</phrase>
<phrase role="keyword">friend</phrase> <phrase role="keyword">void</phrase> <phrase role="identifier">intrusive_ptr_release</phrase><phrase role="special">(</phrase> <phrase role="identifier">yield_completion</phrase> <phrase role="special">*</phrase> <phrase role="identifier">yc</phrase><phrase role="special">)</phrase> <phrase role="keyword">noexcept</phrase> <phrase role="special">{</phrase>
<phrase role="identifier">BOOST_ASSERT</phrase><phrase role="special">(</phrase> <phrase role="keyword">nullptr</phrase> <phrase role="special">!=</phrase> <phrase role="identifier">yc</phrase><phrase role="special">);</phrase>
<phrase role="keyword">if</phrase> <phrase role="special">(</phrase> <phrase role="number">1</phrase> <phrase role="special">==</phrase> <phrase role="identifier">yc</phrase><phrase role="special">-&gt;</phrase><phrase role="identifier">use_count_</phrase><phrase role="special">.</phrase><phrase role="identifier">fetch_sub</phrase><phrase role="special">(</phrase> <phrase role="number">1</phrase><phrase role="special">,</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">memory_order_release</phrase><phrase role="special">)</phrase> <phrase role="special">)</phrase> <phrase role="special">{</phrase>
<phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">atomic_thread_fence</phrase><phrase role="special">(</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">memory_order_acquire</phrase><phrase role="special">);</phrase>
<phrase role="keyword">delete</phrase> <phrase role="identifier">yc</phrase><phrase role="special">;</phrase>
<phrase role="special">}</phrase>
<phrase role="special">}</phrase>
<phrase role="special">};</phrase>
</programlisting>
</para>
<para>
Supposing that the pending async operation has not yet completed, <code><phrase
role="identifier">yield_completion</phrase><phrase role="special">::</phrase><phrase
role="identifier">completed_</phrase></code> will still be <code><phrase
role="keyword">false</phrase></code>, and <code><phrase role="identifier">wait</phrase><phrase
role="special">()</phrase></code> will call <link linkend="context_suspend"><code>context::suspend()</code></link> on
the currently-running fiber.
</para>
<para>
Other fibers will now have a chance to run.
</para>
<para>
Some time later, the async operation completes. It calls <code><phrase role="identifier">yield_handler</phrase><phrase
role="special">&lt;</phrase><phrase role="keyword">void</phrase><phrase role="special">&gt;::</phrase><phrase
role="keyword">operator</phrase><phrase role="special">()(</phrase><phrase
role="identifier">error_code</phrase> <phrase role="keyword">const</phrase><phrase
role="special">&amp;)</phrase></code> with an <code><phrase role="identifier">error_code</phrase></code>
indicating either success or failure. We&#8217;ll consider both cases.
</para>
<para>
<code><phrase role="identifier">yield_handler</phrase><phrase role="special">&lt;</phrase><phrase
role="keyword">void</phrase><phrase role="special">&gt;</phrase></code> explicitly
inherits <code><phrase role="keyword">operator</phrase><phrase role="special">()(</phrase><phrase
role="identifier">error_code</phrase> <phrase role="keyword">const</phrase><phrase
role="special">&amp;)</phrase></code> from <code><phrase role="identifier">yield_handler_base</phrase></code>.
</para>
<para>
<code><phrase role="identifier">yield_handler_base</phrase><phrase role="special">::</phrase><phrase
role="keyword">operator</phrase><phrase role="special">()(</phrase><phrase
role="identifier">error_code</phrase> <phrase role="keyword">const</phrase><phrase
role="special">&amp;)</phrase></code> first sets <code><phrase role="identifier">yield_completion</phrase><phrase
role="special">::</phrase><phrase role="identifier">completed_</phrase></code>
<code><phrase role="keyword">true</phrase></code>. This way, if <code><phrase
role="identifier">async_something</phrase><phrase role="special">()</phrase></code>&#8217;s
async operation completes immediately &mdash; if <code><phrase role="identifier">yield_handler_base</phrase><phrase
role="special">::</phrase><phrase role="keyword">operator</phrase><phrase
role="special">()</phrase></code> is called even before <code><phrase role="identifier">async_result_base</phrase><phrase
role="special">::</phrase><phrase role="identifier">get</phrase><phrase role="special">()</phrase></code>
&mdash; the calling fiber will <emphasis>not</emphasis> suspend.
</para>
<para>
The actual <code><phrase role="identifier">error_code</phrase></code> produced
by the async operation is then stored through the stored <code><phrase role="identifier">yield_t</phrase><phrase
role="special">::</phrase><phrase role="identifier">ec_</phrase></code> pointer.
If <code><phrase role="identifier">async_something</phrase><phrase role="special">()</phrase></code>&#8217;s
caller used (e.g.) <code><phrase role="identifier">yield</phrase><phrase
role="special">[</phrase><phrase role="identifier">my_ec</phrase><phrase
role="special">]</phrase></code> to bind a local <code><phrase role="identifier">error_code</phrase></code>
instance, the actual <code><phrase role="identifier">error_code</phrase></code>
value is stored into the caller&#8217;s variable. Otherwise, it is stored into
<code><phrase role="identifier">async_result_base</phrase><phrase role="special">::</phrase><phrase
role="identifier">ec_</phrase></code>.
</para>
<para>
If the stored fiber context <code><phrase role="identifier">yield_handler_base</phrase><phrase
role="special">::</phrase><phrase role="identifier">ctx_</phrase></code>
is not already running, it is marked as ready to run by passing it to <link linkend="context_schedule"><code>context::schedule()</code></link>.
Control then returns from <code><phrase role="identifier">yield_handler_base</phrase><phrase
role="special">::</phrase><phrase role="keyword">operator</phrase><phrase
role="special">()</phrase></code>: the callback is done.
</para>
<para>
In due course, that fiber is resumed. Control returns from <link linkend="context_suspend"><code>context::suspend()</code></link> to
<code><phrase role="identifier">yield_completion</phrase><phrase role="special">::</phrase><phrase
role="identifier">wait</phrase><phrase role="special">()</phrase></code>,
which returns to <code><phrase role="identifier">async_result_base</phrase><phrase
role="special">::</phrase><phrase role="identifier">get</phrase><phrase role="special">()</phrase></code>.
</para>
<itemizedlist>
<listitem>
<simpara>
If the original caller passed <code><phrase role="identifier">yield</phrase><phrase
role="special">[</phrase><phrase role="identifier">my_ec</phrase><phrase
role="special">]</phrase></code> to <code><phrase role="identifier">async_something</phrase><phrase
role="special">()</phrase></code> to bind a local <code><phrase role="identifier">error_code</phrase></code>
instance, then <code><phrase role="identifier">yield_handler_base</phrase><phrase
role="special">::</phrase><phrase role="keyword">operator</phrase><phrase
role="special">()</phrase></code> stored its <code><phrase role="identifier">error_code</phrase></code>
to the caller&#8217;s <code><phrase role="identifier">my_ec</phrase></code>
instance, leaving <code><phrase role="identifier">async_result_base</phrase><phrase
role="special">::</phrase><phrase role="identifier">ec_</phrase></code>
initialized to success.
</simpara>
</listitem>
<listitem>
<simpara>
If the original caller passed <code><phrase role="identifier">yield</phrase></code>
to <code><phrase role="identifier">async_something</phrase><phrase role="special">()</phrase></code>
without binding a local <code><phrase role="identifier">error_code</phrase></code>
variable, then <code><phrase role="identifier">yield_handler_base</phrase><phrase
role="special">::</phrase><phrase role="keyword">operator</phrase><phrase
role="special">()</phrase></code> stored its <code><phrase role="identifier">error_code</phrase></code>
into <code><phrase role="identifier">async_result_base</phrase><phrase
role="special">::</phrase><phrase role="identifier">ec_</phrase></code>.
If in fact that <code><phrase role="identifier">error_code</phrase></code>
is success, then all is well.
</simpara>
</listitem>
<listitem>
<simpara>
Otherwise &mdash; the original caller did not bind a local <code><phrase role="identifier">error_code</phrase></code>
and <code><phrase role="identifier">yield_handler_base</phrase><phrase
role="special">::</phrase><phrase role="keyword">operator</phrase><phrase
role="special">()</phrase></code> was called with an <code><phrase role="identifier">error_code</phrase></code>
indicating error &mdash; <code><phrase role="identifier">async_result_base</phrase><phrase
role="special">::</phrase><phrase role="identifier">get</phrase><phrase
role="special">()</phrase></code> throws <code><phrase role="identifier">system_error</phrase></code>
with that <code><phrase role="identifier">error_code</phrase></code>.
</simpara>
</listitem>
</itemizedlist>
<para>
The case in which <code><phrase role="identifier">async_something</phrase><phrase
role="special">()</phrase></code>&#8217;s completion callback has signature <code><phrase
role="keyword">void</phrase><phrase role="special">()</phrase></code> is
similar. <code><phrase role="identifier">yield_handler</phrase><phrase role="special">&lt;</phrase><phrase
role="keyword">void</phrase><phrase role="special">&gt;::</phrase><phrase
role="keyword">operator</phrase><phrase role="special">()()</phrase></code>
invokes the machinery above with a <quote>success</quote> <code><phrase role="identifier">error_code</phrase></code>.
</para>
<para>
A completion callback with signature <code><phrase role="keyword">void</phrase><phrase
role="special">(</phrase><phrase role="identifier">error_code</phrase><phrase
role="special">,</phrase> <phrase role="identifier">T</phrase><phrase role="special">)</phrase></code>
(that is: in addition to <code><phrase role="identifier">error_code</phrase></code>,
callback receives some data item) is handled somewhat differently. For this
kind of signature, <code><phrase role="identifier">handler_type</phrase><phrase
role="special">&lt;&gt;::</phrase><phrase role="identifier">type</phrase></code>
specifies <code><phrase role="identifier">yield_handler</phrase><phrase role="special">&lt;</phrase><phrase
role="identifier">T</phrase><phrase role="special">&gt;</phrase></code> (for
<code><phrase role="identifier">T</phrase></code> other than <code><phrase
role="keyword">void</phrase></code>).
</para>
<para>
A <code><phrase role="identifier">yield_handler</phrase><phrase role="special">&lt;</phrase><phrase
role="identifier">T</phrase><phrase role="special">&gt;</phrase></code> reserves
a <code><phrase role="identifier">value_</phrase></code> pointer to a value
of type <code><phrase role="identifier">T</phrase></code>:
</para>
<para>
<programlisting><phrase role="comment">// asio uses handler_type&lt;completion token type, signature&gt;::type to decide</phrase>
<phrase role="comment">// what to instantiate as the actual handler. Below, we specialize</phrase>
<phrase role="comment">// handler_type&lt; yield_t, ... &gt; to indicate yield_handler&lt;&gt;. So when you pass</phrase>
<phrase role="comment">// an instance of yield_t as an asio completion token, asio selects</phrase>
<phrase role="comment">// yield_handler&lt;&gt; as the actual handler class.</phrase>
<phrase role="keyword">template</phrase><phrase role="special">&lt;</phrase> <phrase role="keyword">typename</phrase> <phrase role="identifier">T</phrase> <phrase role="special">&gt;</phrase>
<phrase role="keyword">class</phrase> <phrase role="identifier">yield_handler</phrase><phrase role="special">:</phrase> <phrase role="keyword">public</phrase> <phrase role="identifier">yield_handler_base</phrase> <phrase role="special">{</phrase>
<phrase role="keyword">public</phrase><phrase role="special">:</phrase>
<phrase role="comment">// asio passes the completion token to the handler constructor</phrase>
<phrase role="keyword">explicit</phrase> <phrase role="identifier">yield_handler</phrase><phrase role="special">(</phrase> <phrase role="identifier">yield_t</phrase> <phrase role="keyword">const</phrase><phrase role="special">&amp;</phrase> <phrase role="identifier">y</phrase><phrase role="special">)</phrase> <phrase role="special">:</phrase>
<phrase role="identifier">yield_handler_base</phrase><phrase role="special">{</phrase> <phrase role="identifier">y</phrase> <phrase role="special">}</phrase> <phrase role="special">{</phrase>
<phrase role="special">}</phrase>
<phrase role="comment">// completion callback passing only value (T)</phrase>
<phrase role="keyword">void</phrase> <phrase role="keyword">operator</phrase><phrase role="special">()(</phrase> <phrase role="identifier">T</phrase> <phrase role="identifier">t</phrase><phrase role="special">)</phrase> <phrase role="special">{</phrase>
<phrase role="comment">// just like callback passing success error_code</phrase>
<phrase role="special">(*</phrase><phrase role="keyword">this</phrase><phrase role="special">)(</phrase> <phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">system</phrase><phrase role="special">::</phrase><phrase role="identifier">error_code</phrase><phrase role="special">(),</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">move</phrase><phrase role="special">(</phrase><phrase role="identifier">t</phrase><phrase role="special">)</phrase> <phrase role="special">);</phrase>
<phrase role="special">}</phrase>
<phrase role="comment">// completion callback passing (error_code, T)</phrase>
<phrase role="keyword">void</phrase> <phrase role="keyword">operator</phrase><phrase role="special">()(</phrase> <phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">system</phrase><phrase role="special">::</phrase><phrase role="identifier">error_code</phrase> <phrase role="keyword">const</phrase><phrase role="special">&amp;</phrase> <phrase role="identifier">ec</phrase><phrase role="special">,</phrase> <phrase role="identifier">T</phrase> <phrase role="identifier">t</phrase><phrase role="special">)</phrase> <phrase role="special">{</phrase>
<phrase role="identifier">BOOST_ASSERT_MSG</phrase><phrase role="special">(</phrase> <phrase role="identifier">value_</phrase><phrase role="special">,</phrase>
<phrase role="string">&quot;Must inject value ptr &quot;</phrase>
<phrase role="string">&quot;before caling yield_handler&lt;T&gt;::operator()()&quot;</phrase><phrase role="special">);</phrase>
<phrase role="comment">// move the value to async_result&lt;&gt; instance BEFORE waking up a</phrase>
<phrase role="comment">// suspended fiber</phrase>
<phrase role="special">*</phrase> <phrase role="identifier">value_</phrase> <phrase role="special">=</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">move</phrase><phrase role="special">(</phrase> <phrase role="identifier">t</phrase><phrase role="special">);</phrase>
<phrase role="comment">// forward the call to base-class completion handler</phrase>
<phrase role="identifier">yield_handler_base</phrase><phrase role="special">::</phrase><phrase role="keyword">operator</phrase><phrase role="special">()(</phrase> <phrase role="identifier">ec</phrase><phrase role="special">);</phrase>
<phrase role="special">}</phrase>
<phrase role="comment">//private:</phrase>
<phrase role="comment">// pointer to destination for eventual value</phrase>
<phrase role="comment">// this must be injected by async_result before operator()() is called</phrase>
<phrase role="identifier">T</phrase> <phrase role="special">*</phrase> <phrase role="identifier">value_</phrase><phrase role="special">{</phrase> <phrase role="keyword">nullptr</phrase> <phrase role="special">};</phrase>
<phrase role="special">};</phrase>
</programlisting>
</para>
<para>
This pointer is initialized to <code><phrase role="keyword">nullptr</phrase></code>.
</para>
<para>
When <code><phrase role="identifier">async_something</phrase><phrase role="special">()</phrase></code>
instantiates <code><phrase role="identifier">async_result</phrase><phrase
role="special">&lt;</phrase><phrase role="identifier">yield_handler</phrase><phrase
role="special">&lt;</phrase><phrase role="identifier">T</phrase><phrase role="special">&gt;&gt;</phrase></code>:
</para>
<para>
<programlisting><phrase role="comment">// asio constructs an async_result&lt;&gt; instance from the yield_handler specified</phrase>
<phrase role="comment">// by handler_type&lt;&gt;::type. A particular asio async method constructs the</phrase>
<phrase role="comment">// yield_handler, constructs this async_result specialization from it, then</phrase>
<phrase role="comment">// returns the result of calling its get() method.</phrase>
<phrase role="keyword">template</phrase><phrase role="special">&lt;</phrase> <phrase role="keyword">typename</phrase> <phrase role="identifier">T</phrase> <phrase role="special">&gt;</phrase>
<phrase role="keyword">class</phrase> <phrase role="identifier">async_result</phrase><phrase role="special">&lt;</phrase> <phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">fibers</phrase><phrase role="special">::</phrase><phrase role="identifier">asio</phrase><phrase role="special">::</phrase><phrase role="identifier">detail</phrase><phrase role="special">::</phrase><phrase role="identifier">yield_handler</phrase><phrase role="special">&lt;</phrase> <phrase role="identifier">T</phrase> <phrase role="special">&gt;</phrase> <phrase role="special">&gt;</phrase> <phrase role="special">:</phrase>
<phrase role="keyword">public</phrase> <phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">fibers</phrase><phrase role="special">::</phrase><phrase role="identifier">asio</phrase><phrase role="special">::</phrase><phrase role="identifier">detail</phrase><phrase role="special">::</phrase><phrase role="identifier">async_result_base</phrase> <phrase role="special">{</phrase>
<phrase role="keyword">public</phrase><phrase role="special">:</phrase>
<phrase role="comment">// type returned by get()</phrase>
<phrase role="keyword">typedef</phrase> <phrase role="identifier">T</phrase> <phrase role="identifier">type</phrase><phrase role="special">;</phrase>
<phrase role="keyword">explicit</phrase> <phrase role="identifier">async_result</phrase><phrase role="special">(</phrase> <phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">fibers</phrase><phrase role="special">::</phrase><phrase role="identifier">asio</phrase><phrase role="special">::</phrase><phrase role="identifier">detail</phrase><phrase role="special">::</phrase><phrase role="identifier">yield_handler</phrase><phrase role="special">&lt;</phrase> <phrase role="identifier">T</phrase> <phrase role="special">&gt;</phrase> <phrase role="special">&amp;</phrase> <phrase role="identifier">h</phrase><phrase role="special">)</phrase> <phrase role="special">:</phrase>
<phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">fibers</phrase><phrase role="special">::</phrase><phrase role="identifier">asio</phrase><phrase role="special">::</phrase><phrase role="identifier">detail</phrase><phrase role="special">::</phrase><phrase role="identifier">async_result_base</phrase><phrase role="special">{</phrase> <phrase role="identifier">h</phrase> <phrase role="special">}</phrase> <phrase role="special">{</phrase>
<phrase role="comment">// Inject ptr to our value_ member into yield_handler&lt;&gt;: result will</phrase>
<phrase role="comment">// be stored here.</phrase>
<phrase role="identifier">h</phrase><phrase role="special">.</phrase><phrase role="identifier">value_</phrase> <phrase role="special">=</phrase> <phrase role="special">&amp;</phrase> <phrase role="identifier">value_</phrase><phrase role="special">;</phrase>
<phrase role="special">}</phrase>
<phrase role="comment">// asio async method returns result of calling get()</phrase>
<phrase role="identifier">type</phrase> <phrase role="identifier">get</phrase><phrase role="special">()</phrase> <phrase role="special">{</phrase>
<phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">fibers</phrase><phrase role="special">::</phrase><phrase role="identifier">asio</phrase><phrase role="special">::</phrase><phrase role="identifier">detail</phrase><phrase role="special">::</phrase><phrase role="identifier">async_result_base</phrase><phrase role="special">::</phrase><phrase role="identifier">get</phrase><phrase role="special">();</phrase>
<phrase role="keyword">return</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">move</phrase><phrase role="special">(</phrase> <phrase role="identifier">value_</phrase><phrase role="special">);</phrase>
<phrase role="special">}</phrase>
<phrase role="keyword">private</phrase><phrase role="special">:</phrase>
<phrase role="identifier">type</phrase> <phrase role="identifier">value_</phrase><phrase role="special">{};</phrase>
<phrase role="special">};</phrase>
</programlisting>
</para>
<para>
this <code><phrase role="identifier">async_result</phrase><phrase role="special">&lt;&gt;</phrase></code>
specialization reserves a member of type <code><phrase role="identifier">T</phrase></code>
to receive the passed data item, and sets <code><phrase role="identifier">yield_handler</phrase><phrase
role="special">&lt;</phrase><phrase role="identifier">T</phrase><phrase role="special">&gt;::</phrase><phrase
role="identifier">value_</phrase></code> to point to its own data member.
</para>
<para>
<code><phrase role="identifier">async_result</phrase><phrase role="special">&lt;</phrase><phrase
role="identifier">yield_handler</phrase><phrase role="special">&lt;</phrase><phrase
role="identifier">T</phrase><phrase role="special">&gt;&gt;</phrase></code>
overrides <code><phrase role="identifier">get</phrase><phrase role="special">()</phrase></code>.
The override calls <code><phrase role="identifier">async_result_base</phrase><phrase
role="special">::</phrase><phrase role="identifier">get</phrase><phrase role="special">()</phrase></code>,
so the calling fiber suspends as described above.
</para>
<para>
<code><phrase role="identifier">yield_handler</phrase><phrase role="special">&lt;</phrase><phrase
role="identifier">T</phrase><phrase role="special">&gt;::</phrase><phrase
role="keyword">operator</phrase><phrase role="special">()(</phrase><phrase
role="identifier">error_code</phrase><phrase role="special">,</phrase> <phrase
role="identifier">T</phrase><phrase role="special">)</phrase></code> stores
its passed <code><phrase role="identifier">T</phrase></code> value into
<code><phrase role="identifier">async_result</phrase><phrase role="special">&lt;</phrase><phrase
role="identifier">yield_handler</phrase><phrase role="special">&lt;</phrase><phrase
role="identifier">T</phrase><phrase role="special">&gt;&gt;::</phrase><phrase
role="identifier">value_</phrase></code>.
</para>
<para>
Then it passes control to <code><phrase role="identifier">yield_handler_base</phrase><phrase
role="special">::</phrase><phrase role="keyword">operator</phrase><phrase
role="special">()(</phrase><phrase role="identifier">error_code</phrase><phrase
role="special">)</phrase></code> to deal with waking the original fiber as
described above.
</para>
<para>
When <code><phrase role="identifier">async_result</phrase><phrase role="special">&lt;</phrase><phrase
role="identifier">yield_handler</phrase><phrase role="special">&lt;</phrase><phrase
role="identifier">T</phrase><phrase role="special">&gt;&gt;::</phrase><phrase
role="identifier">get</phrase><phrase role="special">()</phrase></code> resumes,
it returns the stored <code><phrase role="identifier">value_</phrase></code>
to <code><phrase role="identifier">async_something</phrase><phrase role="special">()</phrase></code>
and ultimately to <code><phrase role="identifier">async_something</phrase><phrase
role="special">()</phrase></code>&#8217;s caller.
</para>
<para>
The case of a callback signature <code><phrase role="keyword">void</phrase><phrase
role="special">(</phrase><phrase role="identifier">T</phrase><phrase role="special">)</phrase></code>
is handled by having <code><phrase role="identifier">yield_handler</phrase><phrase
role="special">&lt;</phrase><phrase role="identifier">T</phrase><phrase role="special">&gt;::</phrase><phrase
role="keyword">operator</phrase><phrase role="special">()(</phrase><phrase
role="identifier">T</phrase><phrase role="special">)</phrase></code> engage
the <code><phrase role="keyword">void</phrase><phrase role="special">(</phrase><phrase
role="identifier">error_code</phrase><phrase role="special">,</phrase> <phrase
role="identifier">T</phrase><phrase role="special">)</phrase></code> machinery,
passing a <quote>success</quote> <code><phrase role="identifier">error_code</phrase></code>.
</para>
<para>
The source code above is found in <ulink url="../../examples/asio/yield.hpp">yield.hpp</ulink>
and <ulink url="../../examples/asio/detail/yield.hpp">detail/yield.hpp</ulink>.
</para>
</section>
</section>
<section id="fiber.nonblocking">
<title><anchor id="nonblocking"/><link linkend="fiber.nonblocking">Integrating
Fibers with Nonblocking I/O</link></title>
<bridgehead renderas="sect3" id="fiber.nonblocking.h0">
<phrase id="fiber.nonblocking.overview"/><link linkend="fiber.nonblocking.overview">Overview</link>
</bridgehead>
<para>
<emphasis>Nonblocking</emphasis> I/O is distinct from <emphasis>asynchronous</emphasis>
I/O. A true async I/O operation promises to initiate the operation and notify
the caller on completion, usually via some sort of callback (as described in
<link linkend="callbacks">Integrating Fibers with Asynchronous Callbacks</link>).
</para>
<para>
In contrast, a nonblocking I/O operation refuses to start at all if it would
be necessary to block, returning an error code such as <ulink url="http://man7.org/linux/man-pages/man3/errno.3.html"><code><phrase
role="identifier">EWOULDBLOCK</phrase></code></ulink>. The operation is performed
only when it can complete immediately. In effect, the caller must repeatedly
retry the operation until it stops returning <code><phrase role="identifier">EWOULDBLOCK</phrase></code>.
</para>
<para>
In a classic event-driven program, it can be something of a headache to use
nonblocking I/O. At the point where the nonblocking I/O is attempted, a return
value of <code><phrase role="identifier">EWOULDBLOCK</phrase></code> requires
the caller to pass control back to the main event loop, arranging to retry
again on the next iteration.
</para>
<para>
Worse, a nonblocking I/O operation might <emphasis>partially</emphasis> succeed.
That means that the relevant business logic must continue receiving control
on every main loop iteration until all required data have been processed: a
doubly-nested loop, implemented as a callback-driven state machine.
</para>
<para>
<emphasis role="bold">Boost.Fiber</emphasis> can simplify this problem immensely.
Once you have integrated with the application's main loop as described in
<link linkend="integration">Sharing a Thread with Another Main Loop</link>,
waiting for the next main-loop iteration is as simple as calling <link linkend="this_fiber_yield"><code>this_fiber::yield()</code></link>.
</para>
<bridgehead renderas="sect3" id="fiber.nonblocking.h1">
<phrase id="fiber.nonblocking.example_nonblocking_api"/><link linkend="fiber.nonblocking.example_nonblocking_api">Example
Nonblocking API</link>
</bridgehead>
<para>
For purposes of illustration, consider this API:
</para>
<para>
<programlisting><phrase role="keyword">class</phrase> <phrase role="identifier">NonblockingAPI</phrase> <phrase role="special">{</phrase>
<phrase role="keyword">public</phrase><phrase role="special">:</phrase>
<phrase role="identifier">NonblockingAPI</phrase><phrase role="special">();</phrase>
<phrase role="comment">// nonblocking operation: may return EWOULDBLOCK</phrase>
<phrase role="keyword">int</phrase> <phrase role="identifier">read</phrase><phrase role="special">(</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">string</phrase> <phrase role="special">&amp;</phrase> <phrase role="identifier">data</phrase><phrase role="special">,</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">size_t</phrase> <phrase role="identifier">desired</phrase><phrase role="special">);</phrase>
<phrase role="special">...</phrase>
<phrase role="special">};</phrase>
</programlisting>
</para>
<bridgehead renderas="sect3" id="fiber.nonblocking.h2">
<phrase id="fiber.nonblocking.polling_for_completion"/><link linkend="fiber.nonblocking.polling_for_completion">Polling
for Completion</link>
</bridgehead>
<para>
We can build a low-level wrapper around <code><phrase role="identifier">NonblockingAPI</phrase><phrase
role="special">::</phrase><phrase role="identifier">read</phrase><phrase role="special">()</phrase></code>
that shields its caller from ever having to deal with <code><phrase role="identifier">EWOULDBLOCK</phrase></code>:
</para>
<para>
<programlisting><phrase role="comment">// guaranteed not to return EWOULDBLOCK</phrase>
<phrase role="keyword">int</phrase> <phrase role="identifier">read_chunk</phrase><phrase role="special">(</phrase> <phrase role="identifier">NonblockingAPI</phrase> <phrase role="special">&amp;</phrase> <phrase role="identifier">api</phrase><phrase role="special">,</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">string</phrase> <phrase role="special">&amp;</phrase> <phrase role="identifier">data</phrase><phrase role="special">,</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">size_t</phrase> <phrase role="identifier">desired</phrase><phrase role="special">)</phrase> <phrase role="special">{</phrase>
<phrase role="keyword">int</phrase> <phrase role="identifier">error</phrase><phrase role="special">;</phrase>
<phrase role="keyword">while</phrase> <phrase role="special">(</phrase> <phrase role="identifier">EWOULDBLOCK</phrase> <phrase role="special">==</phrase> <phrase role="special">(</phrase> <phrase role="identifier">error</phrase> <phrase role="special">=</phrase> <phrase role="identifier">api</phrase><phrase role="special">.</phrase><phrase role="identifier">read</phrase><phrase role="special">(</phrase> <phrase role="identifier">data</phrase><phrase role="special">,</phrase> <phrase role="identifier">desired</phrase><phrase role="special">)</phrase> <phrase role="special">)</phrase> <phrase role="special">)</phrase> <phrase role="special">{</phrase>
<phrase role="comment">// not ready yet -- try again on the next iteration of the</phrase>
<phrase role="comment">// application's main loop</phrase>
<phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">this_fiber</phrase><phrase role="special">::</phrase><phrase role="identifier">yield</phrase><phrase role="special">();</phrase>
<phrase role="special">}</phrase>
<phrase role="keyword">return</phrase> <phrase role="identifier">error</phrase><phrase role="special">;</phrase>
<phrase role="special">}</phrase>
</programlisting>
</para>
<bridgehead renderas="sect3" id="fiber.nonblocking.h3">
<phrase id="fiber.nonblocking.filling_all_desired_data"/><link linkend="fiber.nonblocking.filling_all_desired_data">Filling
All Desired Data</link>
</bridgehead>
<para>
Given <code><phrase role="identifier">read_chunk</phrase><phrase role="special">()</phrase></code>,
we can straightforwardly iterate until we have all desired data:
</para>
<para>
<programlisting><phrase role="comment">// keep reading until desired length, EOF or error</phrase>
<phrase role="comment">// may return both partial data and nonzero error</phrase>
<phrase role="keyword">int</phrase> <phrase role="identifier">read_desired</phrase><phrase role="special">(</phrase> <phrase role="identifier">NonblockingAPI</phrase> <phrase role="special">&amp;</phrase> <phrase role="identifier">api</phrase><phrase role="special">,</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">string</phrase> <phrase role="special">&amp;</phrase> <phrase role="identifier">data</phrase><phrase role="special">,</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">size_t</phrase> <phrase role="identifier">desired</phrase><phrase role="special">)</phrase> <phrase role="special">{</phrase>
<phrase role="comment">// we're going to accumulate results into 'data'</phrase>
<phrase role="identifier">data</phrase><phrase role="special">.</phrase><phrase role="identifier">clear</phrase><phrase role="special">();</phrase>
<phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">string</phrase> <phrase role="identifier">chunk</phrase><phrase role="special">;</phrase>
<phrase role="keyword">int</phrase> <phrase role="identifier">error</phrase> <phrase role="special">=</phrase> <phrase role="number">0</phrase><phrase role="special">;</phrase>
<phrase role="keyword">while</phrase> <phrase role="special">(</phrase> <phrase role="identifier">data</phrase><phrase role="special">.</phrase><phrase role="identifier">length</phrase><phrase role="special">()</phrase> <phrase role="special">&lt;</phrase> <phrase role="identifier">desired</phrase> <phrase role="special">&amp;&amp;</phrase>
<phrase role="special">(</phrase> <phrase role="identifier">error</phrase> <phrase role="special">=</phrase> <phrase role="identifier">read_chunk</phrase><phrase role="special">(</phrase> <phrase role="identifier">api</phrase><phrase role="special">,</phrase> <phrase role="identifier">chunk</phrase><phrase role="special">,</phrase> <phrase role="identifier">desired</phrase> <phrase role="special">-</phrase> <phrase role="identifier">data</phrase><phrase role="special">.</phrase><phrase role="identifier">length</phrase><phrase role="special">()</phrase> <phrase role="special">)</phrase> <phrase role="special">)</phrase> <phrase role="special">==</phrase> <phrase role="number">0</phrase><phrase role="special">)</phrase> <phrase role="special">{</phrase>
<phrase role="identifier">data</phrase><phrase role="special">.</phrase><phrase role="identifier">append</phrase><phrase role="special">(</phrase> <phrase role="identifier">chunk</phrase><phrase role="special">);</phrase>
<phrase role="special">}</phrase>
<phrase role="keyword">return</phrase> <phrase role="identifier">error</phrase><phrase role="special">;</phrase>
<phrase role="special">}</phrase>
</programlisting>
</para>
<para>
(Of <emphasis>course</emphasis> there are more efficient ways to accumulate
string data. That's not the point of this example.)
</para>
<bridgehead renderas="sect3" id="fiber.nonblocking.h4">
<phrase id="fiber.nonblocking.wrapping_it_up"/><link linkend="fiber.nonblocking.wrapping_it_up">Wrapping
it Up</link>
</bridgehead>
<para>
Finally, we can define a relevant exception:
</para>
<para>
<programlisting><phrase role="comment">// exception class augmented with both partially-read data and errorcode</phrase>
<phrase role="keyword">class</phrase> <phrase role="identifier">IncompleteRead</phrase> <phrase role="special">:</phrase> <phrase role="keyword">public</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">runtime_error</phrase> <phrase role="special">{</phrase>
<phrase role="keyword">public</phrase><phrase role="special">:</phrase>
<phrase role="identifier">IncompleteRead</phrase><phrase role="special">(</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">string</phrase> <phrase role="keyword">const</phrase><phrase role="special">&amp;</phrase> <phrase role="identifier">what</phrase><phrase role="special">,</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">string</phrase> <phrase role="keyword">const</phrase><phrase role="special">&amp;</phrase> <phrase role="identifier">partial</phrase><phrase role="special">,</phrase> <phrase role="keyword">int</phrase> <phrase role="identifier">ec</phrase><phrase role="special">)</phrase> <phrase role="special">:</phrase>
<phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">runtime_error</phrase><phrase role="special">(</phrase> <phrase role="identifier">what</phrase><phrase role="special">),</phrase>
<phrase role="identifier">partial_</phrase><phrase role="special">(</phrase> <phrase role="identifier">partial</phrase><phrase role="special">),</phrase>
<phrase role="identifier">ec_</phrase><phrase role="special">(</phrase> <phrase role="identifier">ec</phrase><phrase role="special">)</phrase> <phrase role="special">{</phrase>
<phrase role="special">}</phrase>
<phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">string</phrase> <phrase role="identifier">get_partial</phrase><phrase role="special">()</phrase> <phrase role="keyword">const</phrase> <phrase role="special">{</phrase>
<phrase role="keyword">return</phrase> <phrase role="identifier">partial_</phrase><phrase role="special">;</phrase>
<phrase role="special">}</phrase>
<phrase role="keyword">int</phrase> <phrase role="identifier">get_errorcode</phrase><phrase role="special">()</phrase> <phrase role="keyword">const</phrase> <phrase role="special">{</phrase>
<phrase role="keyword">return</phrase> <phrase role="identifier">ec_</phrase><phrase role="special">;</phrase>
<phrase role="special">}</phrase>
<phrase role="keyword">private</phrase><phrase role="special">:</phrase>
<phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">string</phrase> <phrase role="identifier">partial_</phrase><phrase role="special">;</phrase>
<phrase role="keyword">int</phrase> <phrase role="identifier">ec_</phrase><phrase role="special">;</phrase>
<phrase role="special">};</phrase>
</programlisting>
</para>
<para>
and write a simple <code><phrase role="identifier">read</phrase><phrase role="special">()</phrase></code>
function that either returns all desired data or throws <code><phrase role="identifier">IncompleteRead</phrase></code>:
</para>
<para>
<programlisting><phrase role="comment">// read all desired data or throw IncompleteRead</phrase>
<phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">string</phrase> <phrase role="identifier">read</phrase><phrase role="special">(</phrase> <phrase role="identifier">NonblockingAPI</phrase> <phrase role="special">&amp;</phrase> <phrase role="identifier">api</phrase><phrase role="special">,</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">size_t</phrase> <phrase role="identifier">desired</phrase><phrase role="special">)</phrase> <phrase role="special">{</phrase>
<phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">string</phrase> <phrase role="identifier">data</phrase><phrase role="special">;</phrase>
<phrase role="keyword">int</phrase> <phrase role="identifier">ec</phrase><phrase role="special">(</phrase> <phrase role="identifier">read_desired</phrase><phrase role="special">(</phrase> <phrase role="identifier">api</phrase><phrase role="special">,</phrase> <phrase role="identifier">data</phrase><phrase role="special">,</phrase> <phrase role="identifier">desired</phrase><phrase role="special">)</phrase> <phrase role="special">);</phrase>
<phrase role="comment">// for present purposes, EOF isn't a failure</phrase>
<phrase role="keyword">if</phrase> <phrase role="special">(</phrase> <phrase role="number">0</phrase> <phrase role="special">==</phrase> <phrase role="identifier">ec</phrase> <phrase role="special">||</phrase> <phrase role="identifier">EOF</phrase> <phrase role="special">==</phrase> <phrase role="identifier">ec</phrase><phrase role="special">)</phrase> <phrase role="special">{</phrase>
<phrase role="keyword">return</phrase> <phrase role="identifier">data</phrase><phrase role="special">;</phrase>
<phrase role="special">}</phrase>
<phrase role="comment">// oh oh, partial read</phrase>
<phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">ostringstream</phrase> <phrase role="identifier">msg</phrase><phrase role="special">;</phrase>
<phrase role="identifier">msg</phrase> <phrase role="special">&lt;&lt;</phrase> <phrase role="string">&quot;NonblockingAPI::read() error &quot;</phrase> <phrase role="special">&lt;&lt;</phrase> <phrase role="identifier">ec</phrase> <phrase role="special">&lt;&lt;</phrase> <phrase role="string">&quot; after &quot;</phrase>
<phrase role="special">&lt;&lt;</phrase> <phrase role="identifier">data</phrase><phrase role="special">.</phrase><phrase role="identifier">length</phrase><phrase role="special">()</phrase> <phrase role="special">&lt;&lt;</phrase> <phrase role="string">&quot; of &quot;</phrase> <phrase role="special">&lt;&lt;</phrase> <phrase role="identifier">desired</phrase> <phrase role="special">&lt;&lt;</phrase> <phrase role="string">&quot; characters&quot;</phrase><phrase role="special">;</phrase>
<phrase role="keyword">throw</phrase> <phrase role="identifier">IncompleteRead</phrase><phrase role="special">(</phrase> <phrase role="identifier">msg</phrase><phrase role="special">.</phrase><phrase role="identifier">str</phrase><phrase role="special">(),</phrase> <phrase role="identifier">data</phrase><phrase role="special">,</phrase> <phrase role="identifier">ec</phrase><phrase role="special">);</phrase>
<phrase role="special">}</phrase>
</programlisting>
</para>
<para>
Once we can transparently wait for the next main-loop iteration using <link linkend="this_fiber_yield"><code>this_fiber::yield()</code></link>,
ordinary encapsulation Just Works.
</para>
<para>
The source code above is found in <ulink url="../../examples/adapt_nonblocking.cpp">adapt_nonblocking.cpp</ulink>.
</para>
</section>
<section id="fiber.when_any">
<title><anchor id="when_any"/><link linkend="fiber.when_any">when_any / when_all
functionality</link></title>
<bridgehead renderas="sect3" id="fiber.when_any.h0">
<phrase id="fiber.when_any.overview"/><link linkend="fiber.when_any.overview">Overview</link>
</bridgehead>
<para>
A bit of wisdom from the early days of computing still holds true today: prefer
to model program state using the instruction pointer rather than with Boolean
flags. In other words, if the program must <quote>do something</quote> and
then do something almost the same, but with minor changes... perhaps parts
of that something should be broken out as smaller separate functions, rather
than introducing flags to alter the internal behavior of a monolithic function.
</para>
<para>
To that we would add: prefer to describe control flow using C++ native constructs
such as function calls, <code><phrase role="keyword">if</phrase></code>, <code><phrase
role="keyword">while</phrase></code>, <code><phrase role="keyword">for</phrase></code>,
<code><phrase role="keyword">do</phrase></code> et al. rather than as chains
of callbacks.
</para>
<para>
One of the great strengths of <emphasis role="bold">Boost.Fiber</emphasis>
is the flexibility it confers on the coder to restructure an application from
chains of callbacks to straightforward C++ statement sequence, even when code
in that fiber is in fact interleaved with code running in other fibers.
</para>
<para>
There has been much recent discussion about the benefits of when_any and when_all
functionality. When dealing with asynchronous and possibly unreliable services,
these are valuable idioms. But of course when_any and when_all are closely
tied to the use of chains of callbacks.
</para>
<para>
This section presents recipes for achieving the same ends, in the context of
a fiber that wants to <quote>do something</quote> when one or more other independent
activities have completed. Accordingly, these are <code><phrase role="identifier">wait_something</phrase><phrase
role="special">()</phrase></code> functions rather than <code><phrase role="identifier">when_something</phrase><phrase
role="special">()</phrase></code> functions. The expectation is that the calling
fiber asks to launch those independent activities, then waits for them, then
sequentially proceeds with whatever processing depends on those results.
</para>
<para>
The function names shown (e.g. <link linkend="wait_first_simple"><code><phrase
role="identifier">wait_first_simple</phrase><phrase role="special">()</phrase></code></link>)
are for illustrative purposes only, because all these functions have been bundled
into a single source file. Presumably, if (say) <link linkend="wait_first_success"><code><phrase
role="identifier">wait_first_success</phrase><phrase role="special">()</phrase></code></link>
best suits your application needs, you could introduce that variant with the
name <code><phrase role="identifier">wait_any</phrase><phrase role="special">()</phrase></code>.
</para>
<note>
<para>
The functions presented in this section accept variadic argument lists of
task functions. Corresponding <code><phrase role="identifier">wait_something</phrase><phrase
role="special">()</phrase></code> functions accepting a container of task
functions are left as an exercise for the interested reader. Those should
actually be simpler. Most of the complexity would arise from overloading
the same name for both purposes.
</para>
</note>
<para>
All the source code for this section is found in <ulink url="../../examples/wait_stuff.cpp">wait_stuff.cpp</ulink>.
</para>
<bridgehead renderas="sect3" id="fiber.when_any.h1">
<phrase id="fiber.when_any.example_task_function"/><link linkend="fiber.when_any.example_task_function">Example
Task Function</link>
</bridgehead>
<para>
<anchor id="wait_sleeper"/>We found it convenient to model an asynchronous
task using this function:
</para>
<para>
<programlisting><phrase role="keyword">template</phrase><phrase role="special">&lt;</phrase> <phrase role="keyword">typename</phrase> <phrase role="identifier">T</phrase> <phrase role="special">&gt;</phrase>
<phrase role="identifier">T</phrase> <phrase role="identifier">sleeper_impl</phrase><phrase role="special">(</phrase> <phrase role="identifier">T</phrase> <phrase role="identifier">item</phrase><phrase role="special">,</phrase> <phrase role="keyword">int</phrase> <phrase role="identifier">ms</phrase><phrase role="special">,</phrase> <phrase role="keyword">bool</phrase> <phrase role="identifier">thrw</phrase> <phrase role="special">=</phrase> <phrase role="keyword">false</phrase><phrase role="special">)</phrase> <phrase role="special">{</phrase>
<phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">ostringstream</phrase> <phrase role="identifier">descb</phrase><phrase role="special">,</phrase> <phrase role="identifier">funcb</phrase><phrase role="special">;</phrase>
<phrase role="identifier">descb</phrase> <phrase role="special">&lt;&lt;</phrase> <phrase role="identifier">item</phrase><phrase role="special">;</phrase>
<phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">string</phrase> <phrase role="identifier">desc</phrase><phrase role="special">(</phrase> <phrase role="identifier">descb</phrase><phrase role="special">.</phrase><phrase role="identifier">str</phrase><phrase role="special">()</phrase> <phrase role="special">);</phrase>
<phrase role="identifier">funcb</phrase> <phrase role="special">&lt;&lt;</phrase> <phrase role="string">&quot; sleeper(&quot;</phrase> <phrase role="special">&lt;&lt;</phrase> <phrase role="identifier">item</phrase> <phrase role="special">&lt;&lt;</phrase> <phrase role="string">&quot;)&quot;</phrase><phrase role="special">;</phrase>
<phrase role="identifier">Verbose</phrase> <phrase role="identifier">v</phrase><phrase role="special">(</phrase> <phrase role="identifier">funcb</phrase><phrase role="special">.</phrase><phrase role="identifier">str</phrase><phrase role="special">()</phrase> <phrase role="special">);</phrase>
<phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">this_fiber</phrase><phrase role="special">::</phrase><phrase role="identifier">sleep_for</phrase><phrase role="special">(</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">chrono</phrase><phrase role="special">::</phrase><phrase role="identifier">milliseconds</phrase><phrase role="special">(</phrase> <phrase role="identifier">ms</phrase><phrase role="special">)</phrase> <phrase role="special">);</phrase>
<phrase role="keyword">if</phrase> <phrase role="special">(</phrase> <phrase role="identifier">thrw</phrase><phrase role="special">)</phrase> <phrase role="special">{</phrase>
<phrase role="keyword">throw</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">runtime_error</phrase><phrase role="special">(</phrase> <phrase role="identifier">desc</phrase><phrase role="special">);</phrase>
<phrase role="special">}</phrase>
<phrase role="keyword">return</phrase> <phrase role="identifier">item</phrase><phrase role="special">;</phrase>
<phrase role="special">}</phrase>
</programlisting>
</para>
<para>
with type-specific <code><phrase role="identifier">sleeper</phrase><phrase
role="special">()</phrase></code> <quote>front ends</quote> for <code><phrase
role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">string</phrase></code>,
<code><phrase role="keyword">double</phrase></code> and <code><phrase role="keyword">int</phrase></code>.
</para>
<para>
<code><phrase role="identifier">Verbose</phrase></code> simply prints a message
to <code><phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase
role="identifier">cout</phrase></code> on construction and destruction.
</para>
<para>
Basically:
</para>
<orderedlist>
<listitem>
<simpara>
<code><phrase role="identifier">sleeper</phrase><phrase role="special">()</phrase></code>
prints a start message;
</simpara>
</listitem>
<listitem>
<simpara>
sleeps for the specified number of milliseconds;
</simpara>
</listitem>
<listitem>
<simpara>
if <code><phrase role="identifier">thrw</phrase></code> is passed as <code><phrase
role="keyword">true</phrase></code>, throws a string description of the
passed <code><phrase role="identifier">item</phrase></code>;
</simpara>
</listitem>
<listitem>
<simpara>
else returns the passed <code><phrase role="identifier">item</phrase></code>.
</simpara>
</listitem>
<listitem>
<simpara>
On the way out, <code><phrase role="identifier">sleeper</phrase><phrase
role="special">()</phrase></code> produces a stop message.
</simpara>
</listitem>
</orderedlist>
<para>
This function will feature in the example calls to the various functions presented
below.
</para>
<section id="fiber.when_any.when_any">
<title><link linkend="fiber.when_any.when_any">when_any</link></title>
<section id="fiber.when_any.when_any.when_any__simple_completion">
<title><anchor id="wait_first_simple_section"/><link linkend="fiber.when_any.when_any.when_any__simple_completion">when_any,
simple completion</link></title>
<para>
The simplest case is when you only need to know that the first of a set
of asynchronous tasks has completed &mdash; but you don't need to obtain a return
value, and you're confident that they will not throw exceptions.
</para>
<para>
<anchor id="wait_done"/>For this we introduce a <code><phrase role="identifier">Done</phrase></code>
class to wrap a <code><phrase role="keyword">bool</phrase></code> variable
with a <link linkend="class_condition_variable"><code>condition_variable</code></link> and a <link linkend="class_mutex"><code>mutex</code></link>:
</para>
<para>
<programlisting><phrase role="comment">// Wrap canonical pattern for condition_variable + bool flag</phrase>
<phrase role="keyword">struct</phrase> <phrase role="identifier">Done</phrase> <phrase role="special">{</phrase>
<phrase role="keyword">private</phrase><phrase role="special">:</phrase>
<phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">fibers</phrase><phrase role="special">::</phrase><phrase role="identifier">condition_variable</phrase> <phrase role="identifier">cond</phrase><phrase role="special">;</phrase>
<phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">fibers</phrase><phrase role="special">::</phrase><phrase role="identifier">mutex</phrase> <phrase role="identifier">mutex</phrase><phrase role="special">;</phrase>
<phrase role="keyword">bool</phrase> <phrase role="identifier">ready</phrase> <phrase role="special">=</phrase> <phrase role="keyword">false</phrase><phrase role="special">;</phrase>
<phrase role="keyword">public</phrase><phrase role="special">:</phrase>
<phrase role="keyword">typedef</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">shared_ptr</phrase><phrase role="special">&lt;</phrase> <phrase role="identifier">Done</phrase> <phrase role="special">&gt;</phrase> <phrase role="identifier">ptr</phrase><phrase role="special">;</phrase>
<phrase role="keyword">void</phrase> <phrase role="identifier">wait</phrase><phrase role="special">()</phrase> <phrase role="special">{</phrase>
<phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">unique_lock</phrase><phrase role="special">&lt;</phrase> <phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">fibers</phrase><phrase role="special">::</phrase><phrase role="identifier">mutex</phrase> <phrase role="special">&gt;</phrase> <phrase role="identifier">lock</phrase><phrase role="special">(</phrase> <phrase role="identifier">mutex</phrase><phrase role="special">);</phrase>
<phrase role="identifier">cond</phrase><phrase role="special">.</phrase><phrase role="identifier">wait</phrase><phrase role="special">(</phrase> <phrase role="identifier">lock</phrase><phrase role="special">,</phrase> <phrase role="special">[</phrase><phrase role="keyword">this</phrase><phrase role="special">](){</phrase> <phrase role="keyword">return</phrase> <phrase role="identifier">ready</phrase><phrase role="special">;</phrase> <phrase role="special">});</phrase>
<phrase role="special">}</phrase>
<phrase role="keyword">void</phrase> <phrase role="identifier">notify</phrase><phrase role="special">()</phrase> <phrase role="special">{</phrase>
<phrase role="special">{</phrase>
<phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">unique_lock</phrase><phrase role="special">&lt;</phrase> <phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">fibers</phrase><phrase role="special">::</phrase><phrase role="identifier">mutex</phrase> <phrase role="special">&gt;</phrase> <phrase role="identifier">lock</phrase><phrase role="special">(</phrase> <phrase role="identifier">mutex</phrase><phrase role="special">);</phrase>
<phrase role="identifier">ready</phrase> <phrase role="special">=</phrase> <phrase role="keyword">true</phrase><phrase role="special">;</phrase>
<phrase role="special">}</phrase> <phrase role="comment">// release mutex</phrase>
<phrase role="identifier">cond</phrase><phrase role="special">.</phrase><phrase role="identifier">notify_one</phrase><phrase role="special">();</phrase>
<phrase role="special">}</phrase>
<phrase role="special">};</phrase>
</programlisting>
</para>
<para>
The pattern we follow throughout this section is to pass a <ulink url="http://www.cplusplus.com/reference/memory/shared_ptr/"><code><phrase
role="identifier">std</phrase><phrase role="special">::</phrase><phrase
role="identifier">shared_ptr</phrase><phrase role="special">&lt;&gt;</phrase></code></ulink>
to the relevant synchronization object to the various tasks' fiber functions.
This eliminates nagging questions about the lifespan of the synchronization
object relative to the last of the fibers.
</para>
<para>
<anchor id="wait_first_simple"/><code><phrase role="identifier">wait_first_simple</phrase><phrase
role="special">()</phrase></code> uses that tactic for <link linkend="wait_done"><code><phrase
role="identifier">Done</phrase></code></link>:
</para>
<para>
<programlisting><phrase role="keyword">template</phrase><phrase role="special">&lt;</phrase> <phrase role="keyword">typename</phrase> <phrase role="special">...</phrase> <phrase role="identifier">Fns</phrase> <phrase role="special">&gt;</phrase>
<phrase role="keyword">void</phrase> <phrase role="identifier">wait_first_simple</phrase><phrase role="special">(</phrase> <phrase role="identifier">Fns</phrase> <phrase role="special">&amp;&amp;</phrase> <phrase role="special">...</phrase> <phrase role="identifier">functions</phrase><phrase role="special">)</phrase> <phrase role="special">{</phrase>
<phrase role="comment">// Use shared_ptr because each function's fiber will bind it separately,</phrase>
<phrase role="comment">// and we're going to return before the last of them completes.</phrase>
<phrase role="keyword">auto</phrase> <phrase role="identifier">done</phrase><phrase role="special">(</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">make_shared</phrase><phrase role="special">&lt;</phrase> <phrase role="identifier">Done</phrase> <phrase role="special">&gt;()</phrase> <phrase role="special">);</phrase>
<phrase role="identifier">wait_first_simple_impl</phrase><phrase role="special">(</phrase> <phrase role="identifier">done</phrase><phrase role="special">,</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">forward</phrase><phrase role="special">&lt;</phrase> <phrase role="identifier">Fns</phrase> <phrase role="special">&gt;(</phrase> <phrase role="identifier">functions</phrase><phrase role="special">)</phrase> <phrase role="special">...</phrase> <phrase role="special">);</phrase>
<phrase role="identifier">done</phrase><phrase role="special">-&gt;</phrase><phrase role="identifier">wait</phrase><phrase role="special">();</phrase>
<phrase role="special">}</phrase>
</programlisting>
</para>
<para>
<anchor id="wait_first_simple_impl"/><code><phrase role="identifier">wait_first_simple_impl</phrase><phrase
role="special">()</phrase></code> is an ordinary recursion over the argument
pack, capturing <code><phrase role="identifier">Done</phrase><phrase role="special">::</phrase><phrase
role="identifier">ptr</phrase></code> for each new fiber:
</para>
<para>
<programlisting><phrase role="comment">// Degenerate case: when there are no functions to wait for, return</phrase>
<phrase role="comment">// immediately.</phrase>
<phrase role="keyword">void</phrase> <phrase role="identifier">wait_first_simple_impl</phrase><phrase role="special">(</phrase> <phrase role="identifier">Done</phrase><phrase role="special">::</phrase><phrase role="identifier">ptr</phrase><phrase role="special">)</phrase> <phrase role="special">{</phrase>
<phrase role="special">}</phrase>
<phrase role="comment">// When there's at least one function to wait for, launch it and recur to</phrase>
<phrase role="comment">// process the rest.</phrase>
<phrase role="keyword">template</phrase><phrase role="special">&lt;</phrase> <phrase role="keyword">typename</phrase> <phrase role="identifier">Fn</phrase><phrase role="special">,</phrase> <phrase role="keyword">typename</phrase> <phrase role="special">...</phrase> <phrase role="identifier">Fns</phrase> <phrase role="special">&gt;</phrase>
<phrase role="keyword">void</phrase> <phrase role="identifier">wait_first_simple_impl</phrase><phrase role="special">(</phrase> <phrase role="identifier">Done</phrase><phrase role="special">::</phrase><phrase role="identifier">ptr</phrase> <phrase role="identifier">done</phrase><phrase role="special">,</phrase> <phrase role="identifier">Fn</phrase> <phrase role="special">&amp;&amp;</phrase> <phrase role="identifier">function</phrase><phrase role="special">,</phrase> <phrase role="identifier">Fns</phrase> <phrase role="special">&amp;&amp;</phrase> <phrase role="special">...</phrase> <phrase role="identifier">functions</phrase><phrase role="special">)</phrase> <phrase role="special">{</phrase>
<phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">fibers</phrase><phrase role="special">::</phrase><phrase role="identifier">fiber</phrase><phrase role="special">(</phrase> <phrase role="special">[</phrase><phrase role="identifier">done</phrase><phrase role="special">,</phrase> <phrase role="identifier">function</phrase><phrase role="special">](){</phrase>
<phrase role="identifier">function</phrase><phrase role="special">();</phrase>
<phrase role="identifier">done</phrase><phrase role="special">-&gt;</phrase><phrase role="identifier">notify</phrase><phrase role="special">();</phrase>
<phrase role="special">}).</phrase><phrase role="identifier">detach</phrase><phrase role="special">();</phrase>
<phrase role="identifier">wait_first_simple_impl</phrase><phrase role="special">(</phrase> <phrase role="identifier">done</phrase><phrase role="special">,</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">forward</phrase><phrase role="special">&lt;</phrase> <phrase role="identifier">Fns</phrase> <phrase role="special">&gt;(</phrase> <phrase role="identifier">functions</phrase><phrase role="special">)</phrase> <phrase role="special">...</phrase> <phrase role="special">);</phrase>
<phrase role="special">}</phrase>
</programlisting>
</para>
<para>
The body of the fiber's lambda is extremely simple, as promised: call the
function, notify <link linkend="wait_done"><code><phrase role="identifier">Done</phrase></code></link>
when it returns. The first fiber to do so allows <code><phrase role="identifier">wait_first_simple</phrase><phrase
role="special">()</phrase></code> to return &mdash; which is why it's useful to
have <code><phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase
role="identifier">shared_ptr</phrase><phrase role="special">&lt;</phrase><phrase
role="identifier">Done</phrase><phrase role="special">&gt;</phrase></code>
manage the lifespan of our <code><phrase role="identifier">Done</phrase></code>
object rather than declaring it as a stack variable in <code><phrase role="identifier">wait_first_simple</phrase><phrase
role="special">()</phrase></code>.
</para>
<para>
This is how you might call it:
</para>
<para>
<programlisting><phrase role="identifier">wait_first_simple</phrase><phrase role="special">(</phrase>
<phrase role="special">[](){</phrase> <phrase role="identifier">sleeper</phrase><phrase role="special">(</phrase><phrase role="string">&quot;wfs_long&quot;</phrase><phrase role="special">,</phrase> <phrase role="number">150</phrase><phrase role="special">);</phrase> <phrase role="special">},</phrase>
<phrase role="special">[](){</phrase> <phrase role="identifier">sleeper</phrase><phrase role="special">(</phrase><phrase role="string">&quot;wfs_medium&quot;</phrase><phrase role="special">,</phrase> <phrase role="number">100</phrase><phrase role="special">);</phrase> <phrase role="special">},</phrase>
<phrase role="special">[](){</phrase> <phrase role="identifier">sleeper</phrase><phrase role="special">(</phrase><phrase role="string">&quot;wfs_short&quot;</phrase><phrase role="special">,</phrase> <phrase role="number">50</phrase><phrase role="special">);</phrase> <phrase role="special">});</phrase>
</programlisting>
</para>
<para>
In this example, control resumes after <code><phrase role="identifier">wait_first_simple</phrase><phrase
role="special">()</phrase></code> when <link linkend="wait_sleeper"><code><phrase
role="identifier">sleeper</phrase><phrase role="special">(</phrase><phrase
role="string">&quot;wfs_short&quot;</phrase><phrase role="special">,</phrase>
<phrase role="number">50</phrase><phrase role="special">)</phrase></code></link>
completes &mdash; even though the other two <code><phrase role="identifier">sleeper</phrase><phrase
role="special">()</phrase></code> fibers are still running.
</para>
</section>
<section id="fiber.when_any.when_any.when_any__return_value">
<title><link linkend="fiber.when_any.when_any.when_any__return_value">when_any,
return value</link></title>
<para>
It seems more useful to add the ability to capture the return value from
the first of the task functions to complete. Again, we assume that none
will throw an exception.
</para>
<para>
One tactic would be to adapt our <link linkend="wait_done"><code><phrase
role="identifier">Done</phrase></code></link> class to store the first
of the return values, rather than a simple <code><phrase role="keyword">bool</phrase></code>.
However, we choose instead to use a <link linkend="class_buffered_channel"><code>buffered_channel&lt;&gt;</code></link>.
We'll only need to enqueue the first value, so we'll <link linkend="buffered_channel_close"><code>buffered_channel::close()</code></link> it
once we've retrieved that value. Subsequent <code><phrase role="identifier">push</phrase><phrase
role="special">()</phrase></code> calls will return <code><phrase role="identifier">closed</phrase></code>.
</para>
<para>
<anchor id="wait_first_value"/>
<programlisting><phrase role="comment">// Assume that all passed functions have the same return type. The return type</phrase>
<phrase role="comment">// of wait_first_value() is the return type of the first passed function. It is</phrase>
<phrase role="comment">// simply invalid to pass NO functions.</phrase>
<phrase role="keyword">template</phrase><phrase role="special">&lt;</phrase> <phrase role="keyword">typename</phrase> <phrase role="identifier">Fn</phrase><phrase role="special">,</phrase> <phrase role="keyword">typename</phrase> <phrase role="special">...</phrase> <phrase role="identifier">Fns</phrase> <phrase role="special">&gt;</phrase>
<phrase role="keyword">typename</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">result_of</phrase><phrase role="special">&lt;</phrase> <phrase role="identifier">Fn</phrase><phrase role="special">()</phrase> <phrase role="special">&gt;::</phrase><phrase role="identifier">type</phrase>
<phrase role="identifier">wait_first_value</phrase><phrase role="special">(</phrase> <phrase role="identifier">Fn</phrase> <phrase role="special">&amp;&amp;</phrase> <phrase role="identifier">function</phrase><phrase role="special">,</phrase> <phrase role="identifier">Fns</phrase> <phrase role="special">&amp;&amp;</phrase> <phrase role="special">...</phrase> <phrase role="identifier">functions</phrase><phrase role="special">)</phrase> <phrase role="special">{</phrase>
<phrase role="keyword">typedef</phrase> <phrase role="keyword">typename</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">result_of</phrase><phrase role="special">&lt;</phrase> <phrase role="identifier">Fn</phrase><phrase role="special">()</phrase> <phrase role="special">&gt;::</phrase><phrase role="identifier">type</phrase> <phrase role="identifier">return_t</phrase><phrase role="special">;</phrase>
<phrase role="keyword">typedef</phrase> <phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">fibers</phrase><phrase role="special">::</phrase><phrase role="identifier">buffered_channel</phrase><phrase role="special">&lt;</phrase> <phrase role="identifier">return_t</phrase> <phrase role="special">&gt;</phrase> <phrase role="identifier">channel_t</phrase><phrase role="special">;</phrase>
<phrase role="keyword">auto</phrase> <phrase role="identifier">chanp</phrase><phrase role="special">(</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">make_shared</phrase><phrase role="special">&lt;</phrase> <phrase role="identifier">channel_t</phrase> <phrase role="special">&gt;(</phrase> <phrase role="number">64</phrase><phrase role="special">)</phrase> <phrase role="special">);</phrase>
<phrase role="comment">// launch all the relevant fibers</phrase>
<phrase role="identifier">wait_first_value_impl</phrase><phrase role="special">&lt;</phrase> <phrase role="identifier">return_t</phrase> <phrase role="special">&gt;(</phrase> <phrase role="identifier">chanp</phrase><phrase role="special">,</phrase>
<phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">forward</phrase><phrase role="special">&lt;</phrase> <phrase role="identifier">Fn</phrase> <phrase role="special">&gt;(</phrase> <phrase role="identifier">function</phrase><phrase role="special">),</phrase>
<phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">forward</phrase><phrase role="special">&lt;</phrase> <phrase role="identifier">Fns</phrase> <phrase role="special">&gt;(</phrase> <phrase role="identifier">functions</phrase><phrase role="special">)</phrase> <phrase role="special">...</phrase> <phrase role="special">);</phrase>
<phrase role="comment">// retrieve the first value</phrase>
<phrase role="identifier">return_t</phrase> <phrase role="identifier">value</phrase><phrase role="special">(</phrase> <phrase role="identifier">chanp</phrase><phrase role="special">-&gt;</phrase><phrase role="identifier">value_pop</phrase><phrase role="special">()</phrase> <phrase role="special">);</phrase>
<phrase role="comment">// close the channel: no subsequent push() has to succeed</phrase>
<phrase role="identifier">chanp</phrase><phrase role="special">-&gt;</phrase><phrase role="identifier">close</phrase><phrase role="special">();</phrase>
<phrase role="keyword">return</phrase> <phrase role="identifier">value</phrase><phrase role="special">;</phrase>
<phrase role="special">}</phrase>
</programlisting>
</para>
<para>
<anchor id="wait_first_value_impl"/>The meat of the <code><phrase role="identifier">wait_first_value_impl</phrase><phrase
role="special">()</phrase></code> function is as you might expect:
</para>
<para>
<programlisting><phrase role="keyword">template</phrase><phrase role="special">&lt;</phrase> <phrase role="keyword">typename</phrase> <phrase role="identifier">T</phrase><phrase role="special">,</phrase> <phrase role="keyword">typename</phrase> <phrase role="identifier">Fn</phrase> <phrase role="special">&gt;</phrase>
<phrase role="keyword">void</phrase> <phrase role="identifier">wait_first_value_impl</phrase><phrase role="special">(</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">shared_ptr</phrase><phrase role="special">&lt;</phrase> <phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">fibers</phrase><phrase role="special">::</phrase><phrase role="identifier">buffered_channel</phrase><phrase role="special">&lt;</phrase> <phrase role="identifier">T</phrase> <phrase role="special">&gt;</phrase> <phrase role="special">&gt;</phrase> <phrase role="identifier">chan</phrase><phrase role="special">,</phrase>
<phrase role="identifier">Fn</phrase> <phrase role="special">&amp;&amp;</phrase> <phrase role="identifier">function</phrase><phrase role="special">)</phrase> <phrase role="special">{</phrase>
<phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">fibers</phrase><phrase role="special">::</phrase><phrase role="identifier">fiber</phrase><phrase role="special">(</phrase> <phrase role="special">[</phrase><phrase role="identifier">chan</phrase><phrase role="special">,</phrase> <phrase role="identifier">function</phrase><phrase role="special">](){</phrase>
<phrase role="comment">// Ignore channel_op_status returned by push():</phrase>
<phrase role="comment">// might be closed; we simply don't care.</phrase>
<phrase role="identifier">chan</phrase><phrase role="special">-&gt;</phrase><phrase role="identifier">push</phrase><phrase role="special">(</phrase> <phrase role="identifier">function</phrase><phrase role="special">()</phrase> <phrase role="special">);</phrase>
<phrase role="special">}).</phrase><phrase role="identifier">detach</phrase><phrase role="special">();</phrase>
<phrase role="special">}</phrase>
</programlisting>
</para>
<para>
It calls the passed function, pushes its return value and ignores the
<code><phrase role="identifier">push</phrase><phrase role="special">()</phrase></code>
result. You might call it like this:
</para>
<para>
<programlisting><phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">string</phrase> <phrase role="identifier">result</phrase> <phrase role="special">=</phrase> <phrase role="identifier">wait_first_value</phrase><phrase role="special">(</phrase>
<phrase role="special">[](){</phrase> <phrase role="keyword">return</phrase> <phrase role="identifier">sleeper</phrase><phrase role="special">(</phrase><phrase role="string">&quot;wfv_third&quot;</phrase><phrase role="special">,</phrase> <phrase role="number">150</phrase><phrase role="special">);</phrase> <phrase role="special">},</phrase>
<phrase role="special">[](){</phrase> <phrase role="keyword">return</phrase> <phrase role="identifier">sleeper</phrase><phrase role="special">(</phrase><phrase role="string">&quot;wfv_second&quot;</phrase><phrase role="special">,</phrase> <phrase role="number">100</phrase><phrase role="special">);</phrase> <phrase role="special">},</phrase>
<phrase role="special">[](){</phrase> <phrase role="keyword">return</phrase> <phrase role="identifier">sleeper</phrase><phrase role="special">(</phrase><phrase role="string">&quot;wfv_first&quot;</phrase><phrase role="special">,</phrase> <phrase role="number">50</phrase><phrase role="special">);</phrase> <phrase role="special">});</phrase>
<phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">cout</phrase> <phrase role="special">&lt;&lt;</phrase> <phrase role="string">&quot;wait_first_value() =&gt; &quot;</phrase> <phrase role="special">&lt;&lt;</phrase> <phrase role="identifier">result</phrase> <phrase role="special">&lt;&lt;</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">endl</phrase><phrase role="special">;</phrase>
<phrase role="identifier">assert</phrase><phrase role="special">(</phrase><phrase role="identifier">result</phrase> <phrase role="special">==</phrase> <phrase role="string">&quot;wfv_first&quot;</phrase><phrase role="special">);</phrase>
</programlisting>
</para>
</section>
<section id="fiber.when_any.when_any.when_any__produce_first_outcome__whether_result_or_exception">
<title><link linkend="fiber.when_any.when_any.when_any__produce_first_outcome__whether_result_or_exception">when_any,
produce first outcome, whether result or exception</link></title>
<para>
We may not be running in an environment in which we can guarantee no exception
will be thrown by any of our task functions. In that case, the above implementations
of <code><phrase role="identifier">wait_first_something</phrase><phrase
role="special">()</phrase></code> would be naïve: as mentioned in <link
linkend="exceptions">the section on Fiber Management</link>, an uncaught
exception in one of our task fibers would cause <code><phrase role="identifier">std</phrase><phrase
role="special">::</phrase><phrase role="identifier">terminate</phrase><phrase
role="special">()</phrase></code> to be called.
</para>
<para>
Let's at least ensure that such an exception would propagate to the fiber
awaiting the first result. We can use <link linkend="class_future"><code>future&lt;&gt;</code></link> to transport
either a return value or an exception. Therefore, we will change <link
linkend="wait_first_value"><code><phrase role="identifier">wait_first_value</phrase><phrase
role="special">()</phrase></code></link>'s <link linkend="class_buffered_channel"><code>buffered_channel&lt;&gt;</code></link> to
hold <code><phrase role="identifier">future</phrase><phrase role="special">&lt;</phrase>
<phrase role="identifier">T</phrase> <phrase role="special">&gt;</phrase></code>
items instead of simply <code><phrase role="identifier">T</phrase></code>.
</para>
<para>
Once we have a <code><phrase role="identifier">future</phrase><phrase role="special">&lt;&gt;</phrase></code>
in hand, all we need do is call <link linkend="future_get"><code>future::get()</code></link>, which will either
return the value or rethrow the exception.
</para>
<para>
<anchor id="wait_first_outcome"/>
<programlisting><phrase role="keyword">template</phrase><phrase role="special">&lt;</phrase> <phrase role="keyword">typename</phrase> <phrase role="identifier">Fn</phrase><phrase role="special">,</phrase> <phrase role="keyword">typename</phrase> <phrase role="special">...</phrase> <phrase role="identifier">Fns</phrase> <phrase role="special">&gt;</phrase>
<phrase role="keyword">typename</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">result_of</phrase><phrase role="special">&lt;</phrase> <phrase role="identifier">Fn</phrase><phrase role="special">()</phrase> <phrase role="special">&gt;::</phrase><phrase role="identifier">type</phrase>
<phrase role="identifier">wait_first_outcome</phrase><phrase role="special">(</phrase> <phrase role="identifier">Fn</phrase> <phrase role="special">&amp;&amp;</phrase> <phrase role="identifier">function</phrase><phrase role="special">,</phrase> <phrase role="identifier">Fns</phrase> <phrase role="special">&amp;&amp;</phrase> <phrase role="special">...</phrase> <phrase role="identifier">functions</phrase><phrase role="special">)</phrase> <phrase role="special">{</phrase>
<phrase role="comment">// In this case, the value we pass through the channel is actually a</phrase>
<phrase role="comment">// future -- which is already ready. future can carry either a value or an</phrase>
<phrase role="comment">// exception.</phrase>
<phrase role="keyword">typedef</phrase> <phrase role="keyword">typename</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">result_of</phrase><phrase role="special">&lt;</phrase> <phrase role="identifier">Fn</phrase><phrase role="special">()</phrase> <phrase role="special">&gt;::</phrase><phrase role="identifier">type</phrase> <phrase role="identifier">return_t</phrase><phrase role="special">;</phrase>
<phrase role="keyword">typedef</phrase> <phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">fibers</phrase><phrase role="special">::</phrase><phrase role="identifier">future</phrase><phrase role="special">&lt;</phrase> <phrase role="identifier">return_t</phrase> <phrase role="special">&gt;</phrase> <phrase role="identifier">future_t</phrase><phrase role="special">;</phrase>
<phrase role="keyword">typedef</phrase> <phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">fibers</phrase><phrase role="special">::</phrase><phrase role="identifier">buffered_channel</phrase><phrase role="special">&lt;</phrase> <phrase role="identifier">future_t</phrase> <phrase role="special">&gt;</phrase> <phrase role="identifier">channel_t</phrase><phrase role="special">;</phrase>
<phrase role="keyword">auto</phrase> <phrase role="identifier">chanp</phrase><phrase role="special">(</phrase><phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">make_shared</phrase><phrase role="special">&lt;</phrase> <phrase role="identifier">channel_t</phrase> <phrase role="special">&gt;(</phrase> <phrase role="number">64</phrase><phrase role="special">)</phrase> <phrase role="special">);</phrase>
<phrase role="comment">// launch all the relevant fibers</phrase>
<phrase role="identifier">wait_first_outcome_impl</phrase><phrase role="special">&lt;</phrase> <phrase role="identifier">return_t</phrase> <phrase role="special">&gt;(</phrase> <phrase role="identifier">chanp</phrase><phrase role="special">,</phrase>
<phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">forward</phrase><phrase role="special">&lt;</phrase> <phrase role="identifier">Fn</phrase> <phrase role="special">&gt;(</phrase> <phrase role="identifier">function</phrase><phrase role="special">),</phrase>
<phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">forward</phrase><phrase role="special">&lt;</phrase> <phrase role="identifier">Fns</phrase> <phrase role="special">&gt;(</phrase> <phrase role="identifier">functions</phrase><phrase role="special">)</phrase> <phrase role="special">...</phrase> <phrase role="special">);</phrase>
<phrase role="comment">// retrieve the first future</phrase>
<phrase role="identifier">future_t</phrase> <phrase role="identifier">future</phrase><phrase role="special">(</phrase> <phrase role="identifier">chanp</phrase><phrase role="special">-&gt;</phrase><phrase role="identifier">value_pop</phrase><phrase role="special">()</phrase> <phrase role="special">);</phrase>
<phrase role="comment">// close the channel: no subsequent push() has to succeed</phrase>
<phrase role="identifier">chanp</phrase><phrase role="special">-&gt;</phrase><phrase role="identifier">close</phrase><phrase role="special">();</phrase>
<phrase role="comment">// either return value or throw exception</phrase>
<phrase role="keyword">return</phrase> <phrase role="identifier">future</phrase><phrase role="special">.</phrase><phrase role="identifier">get</phrase><phrase role="special">();</phrase>
<phrase role="special">}</phrase>
</programlisting>
</para>
<para>
So far so good &mdash; but there's a timing issue. How should we obtain the <code><phrase
role="identifier">future</phrase><phrase role="special">&lt;&gt;</phrase></code>
to <link linkend="buffered_channel_push"><code>buffered_channel::push()</code></link> on the queue?
</para>
<para>
We could call <link linkend="fibers_async"><code>fibers::async()</code></link>. That would certainly produce
a <code><phrase role="identifier">future</phrase><phrase role="special">&lt;&gt;</phrase></code>
for the task function. The trouble is that it would return too quickly!
We only want <code><phrase role="identifier">future</phrase><phrase role="special">&lt;&gt;</phrase></code>
items for <emphasis>completed</emphasis> tasks on our <code><phrase role="identifier">queue</phrase><phrase
role="special">&lt;&gt;</phrase></code>. In fact, we only want the <code><phrase
role="identifier">future</phrase><phrase role="special">&lt;&gt;</phrase></code>
for the one that completes first. If each fiber launched by <code><phrase
role="identifier">wait_first_outcome</phrase><phrase role="special">()</phrase></code>
were to <code><phrase role="identifier">push</phrase><phrase role="special">()</phrase></code>
the result of calling <code><phrase role="identifier">async</phrase><phrase
role="special">()</phrase></code>, the queue would only ever report the
result of the leftmost task item &mdash; <emphasis>not</emphasis> the one that
completes most quickly.
</para>
<para>
Calling <link linkend="future_get"><code>future::get()</code></link> on the future returned by <code><phrase
role="identifier">async</phrase><phrase role="special">()</phrase></code>
wouldn't be right. You can only call <code><phrase role="identifier">get</phrase><phrase
role="special">()</phrase></code> once per <code><phrase role="identifier">future</phrase><phrase
role="special">&lt;&gt;</phrase></code> instance! And if there were an
exception, it would be rethrown inside the helper fiber at the producer
end of the queue, rather than propagated to the consumer end.
</para>
<para>
We could call <link linkend="future_wait"><code>future::wait()</code></link>. That would block the helper fiber
until the <code><phrase role="identifier">future</phrase><phrase role="special">&lt;&gt;</phrase></code>
became ready, at which point we could <code><phrase role="identifier">push</phrase><phrase
role="special">()</phrase></code> it to be retrieved by <code><phrase role="identifier">wait_first_outcome</phrase><phrase
role="special">()</phrase></code>.
</para>
<para>
That would work &mdash; but there's a simpler tactic that avoids creating an extra
fiber. We can wrap the task function in a <link linkend="class_packaged_task"><code>packaged_task&lt;&gt;</code></link>.
While one naturally thinks of passing a <code><phrase role="identifier">packaged_task</phrase><phrase
role="special">&lt;&gt;</phrase></code> to a new fiber &mdash; that is, in fact,
what <code><phrase role="identifier">async</phrase><phrase role="special">()</phrase></code>
does &mdash; in this case, we're already running in the helper fiber at the producer
end of the queue! We can simply <emphasis>call</emphasis> the <code><phrase
role="identifier">packaged_task</phrase><phrase role="special">&lt;&gt;</phrase></code>.
On return from that call, the task function has completed, meaning that
the <code><phrase role="identifier">future</phrase><phrase role="special">&lt;&gt;</phrase></code>
obtained from the <code><phrase role="identifier">packaged_task</phrase><phrase
role="special">&lt;&gt;</phrase></code> is certain to be ready. At that
point we can simply <code><phrase role="identifier">push</phrase><phrase
role="special">()</phrase></code> it to the queue.
</para>
<para>
<anchor id="wait_first_outcome_impl"/>
<programlisting><phrase role="keyword">template</phrase><phrase role="special">&lt;</phrase> <phrase role="keyword">typename</phrase> <phrase role="identifier">T</phrase><phrase role="special">,</phrase> <phrase role="keyword">typename</phrase> <phrase role="identifier">CHANP</phrase><phrase role="special">,</phrase> <phrase role="keyword">typename</phrase> <phrase role="identifier">Fn</phrase> <phrase role="special">&gt;</phrase>
<phrase role="keyword">void</phrase> <phrase role="identifier">wait_first_outcome_impl</phrase><phrase role="special">(</phrase> <phrase role="identifier">CHANP</phrase> <phrase role="identifier">chan</phrase><phrase role="special">,</phrase> <phrase role="identifier">Fn</phrase> <phrase role="special">&amp;&amp;</phrase> <phrase role="identifier">function</phrase><phrase role="special">)</phrase> <phrase role="special">{</phrase>
<phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">fibers</phrase><phrase role="special">::</phrase><phrase role="identifier">fiber</phrase><phrase role="special">(</phrase>
<phrase role="comment">// Use std::bind() here for C++11 compatibility. C++11 lambda capture</phrase>
<phrase role="comment">// can't move a move-only Fn type, but bind() can. Let bind() move the</phrase>
<phrase role="comment">// channel pointer and the function into the bound object, passing</phrase>
<phrase role="comment">// references into the lambda.</phrase>
<phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">bind</phrase><phrase role="special">(</phrase>
<phrase role="special">[](</phrase> <phrase role="identifier">CHANP</phrase> <phrase role="special">&amp;</phrase> <phrase role="identifier">chan</phrase><phrase role="special">,</phrase>
<phrase role="keyword">typename</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">decay</phrase><phrase role="special">&lt;</phrase> <phrase role="identifier">Fn</phrase> <phrase role="special">&gt;::</phrase><phrase role="identifier">type</phrase> <phrase role="special">&amp;</phrase> <phrase role="identifier">function</phrase><phrase role="special">)</phrase> <phrase role="special">{</phrase>
<phrase role="comment">// Instantiate a packaged_task to capture any exception thrown by</phrase>
<phrase role="comment">// function.</phrase>
<phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">fibers</phrase><phrase role="special">::</phrase><phrase role="identifier">packaged_task</phrase><phrase role="special">&lt;</phrase> <phrase role="identifier">T</phrase><phrase role="special">()</phrase> <phrase role="special">&gt;</phrase> <phrase role="identifier">task</phrase><phrase role="special">(</phrase> <phrase role="identifier">function</phrase><phrase role="special">);</phrase>
<phrase role="comment">// Immediately run this packaged_task on same fiber. We want</phrase>
<phrase role="comment">// function() to have completed BEFORE we push the future.</phrase>
<phrase role="identifier">task</phrase><phrase role="special">();</phrase>
<phrase role="comment">// Pass the corresponding future to consumer. Ignore</phrase>
<phrase role="comment">// channel_op_status returned by push(): might be closed; we</phrase>
<phrase role="comment">// simply don't care.</phrase>
<phrase role="identifier">chan</phrase><phrase role="special">-&gt;</phrase><phrase role="identifier">push</phrase><phrase role="special">(</phrase> <phrase role="identifier">task</phrase><phrase role="special">.</phrase><phrase role="identifier">get_future</phrase><phrase role="special">()</phrase> <phrase role="special">);</phrase>
<phrase role="special">},</phrase>
<phrase role="identifier">chan</phrase><phrase role="special">,</phrase>
<phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">forward</phrase><phrase role="special">&lt;</phrase> <phrase role="identifier">Fn</phrase> <phrase role="special">&gt;(</phrase> <phrase role="identifier">function</phrase><phrase role="special">)</phrase>
<phrase role="special">)).</phrase><phrase role="identifier">detach</phrase><phrase role="special">();</phrase>
<phrase role="special">}</phrase>
</programlisting>
</para>
<para>
Calling it might look like this:
</para>
<para>
<programlisting><phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">string</phrase> <phrase role="identifier">result</phrase> <phrase role="special">=</phrase> <phrase role="identifier">wait_first_outcome</phrase><phrase role="special">(</phrase>
<phrase role="special">[](){</phrase> <phrase role="keyword">return</phrase> <phrase role="identifier">sleeper</phrase><phrase role="special">(</phrase><phrase role="string">&quot;wfos_first&quot;</phrase><phrase role="special">,</phrase> <phrase role="number">50</phrase><phrase role="special">);</phrase> <phrase role="special">},</phrase>
<phrase role="special">[](){</phrase> <phrase role="keyword">return</phrase> <phrase role="identifier">sleeper</phrase><phrase role="special">(</phrase><phrase role="string">&quot;wfos_second&quot;</phrase><phrase role="special">,</phrase> <phrase role="number">100</phrase><phrase role="special">);</phrase> <phrase role="special">},</phrase>
<phrase role="special">[](){</phrase> <phrase role="keyword">return</phrase> <phrase role="identifier">sleeper</phrase><phrase role="special">(</phrase><phrase role="string">&quot;wfos_third&quot;</phrase><phrase role="special">,</phrase> <phrase role="number">150</phrase><phrase role="special">);</phrase> <phrase role="special">});</phrase>
<phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">cout</phrase> <phrase role="special">&lt;&lt;</phrase> <phrase role="string">&quot;wait_first_outcome(success) =&gt; &quot;</phrase> <phrase role="special">&lt;&lt;</phrase> <phrase role="identifier">result</phrase> <phrase role="special">&lt;&lt;</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">endl</phrase><phrase role="special">;</phrase>
<phrase role="identifier">assert</phrase><phrase role="special">(</phrase><phrase role="identifier">result</phrase> <phrase role="special">==</phrase> <phrase role="string">&quot;wfos_first&quot;</phrase><phrase role="special">);</phrase>
<phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">string</phrase> <phrase role="identifier">thrown</phrase><phrase role="special">;</phrase>
<phrase role="keyword">try</phrase> <phrase role="special">{</phrase>
<phrase role="identifier">result</phrase> <phrase role="special">=</phrase> <phrase role="identifier">wait_first_outcome</phrase><phrase role="special">(</phrase>
<phrase role="special">[](){</phrase> <phrase role="keyword">return</phrase> <phrase role="identifier">sleeper</phrase><phrase role="special">(</phrase><phrase role="string">&quot;wfof_first&quot;</phrase><phrase role="special">,</phrase> <phrase role="number">50</phrase><phrase role="special">,</phrase> <phrase role="keyword">true</phrase><phrase role="special">);</phrase> <phrase role="special">},</phrase>
<phrase role="special">[](){</phrase> <phrase role="keyword">return</phrase> <phrase role="identifier">sleeper</phrase><phrase role="special">(</phrase><phrase role="string">&quot;wfof_second&quot;</phrase><phrase role="special">,</phrase> <phrase role="number">100</phrase><phrase role="special">);</phrase> <phrase role="special">},</phrase>
<phrase role="special">[](){</phrase> <phrase role="keyword">return</phrase> <phrase role="identifier">sleeper</phrase><phrase role="special">(</phrase><phrase role="string">&quot;wfof_third&quot;</phrase><phrase role="special">,</phrase> <phrase role="number">150</phrase><phrase role="special">);</phrase> <phrase role="special">});</phrase>
<phrase role="special">}</phrase> <phrase role="keyword">catch</phrase> <phrase role="special">(</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">exception</phrase> <phrase role="keyword">const</phrase><phrase role="special">&amp;</phrase> <phrase role="identifier">e</phrase><phrase role="special">)</phrase> <phrase role="special">{</phrase>
<phrase role="identifier">thrown</phrase> <phrase role="special">=</phrase> <phrase role="identifier">e</phrase><phrase role="special">.</phrase><phrase role="identifier">what</phrase><phrase role="special">();</phrase>
<phrase role="special">}</phrase>
<phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">cout</phrase> <phrase role="special">&lt;&lt;</phrase> <phrase role="string">&quot;wait_first_outcome(fail) threw '&quot;</phrase> <phrase role="special">&lt;&lt;</phrase> <phrase role="identifier">thrown</phrase>
<phrase role="special">&lt;&lt;</phrase> <phrase role="string">&quot;'&quot;</phrase> <phrase role="special">&lt;&lt;</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">endl</phrase><phrase role="special">;</phrase>
<phrase role="identifier">assert</phrase><phrase role="special">(</phrase><phrase role="identifier">thrown</phrase> <phrase role="special">==</phrase> <phrase role="string">&quot;wfof_first&quot;</phrase><phrase role="special">);</phrase>
</programlisting>
</para>
</section>
<section id="fiber.when_any.when_any.when_any__produce_first_success">
<title><link linkend="fiber.when_any.when_any.when_any__produce_first_success">when_any,
produce first success</link></title>
<para>
One scenario for <quote>when_any</quote> functionality is when we're redundantly
contacting some number of possibly-unreliable web services. Not only might
they be slow &mdash; any one of them might produce a failure rather than the desired
result.
</para>
<para>
In such a case, <link linkend="wait_first_outcome"><code><phrase role="identifier">wait_first_outcome</phrase><phrase
role="special">()</phrase></code></link> isn't the right approach. If one
of the services produces an error quickly, while another follows up with
a real answer, we don't want to prefer the error just because it arrived
first!
</para>
<para>
Given the <code><phrase role="identifier">queue</phrase><phrase role="special">&lt;</phrase>
<phrase role="identifier">future</phrase><phrase role="special">&lt;</phrase>
<phrase role="identifier">T</phrase> <phrase role="special">&gt;</phrase>
<phrase role="special">&gt;</phrase></code> we already constructed for
<code><phrase role="identifier">wait_first_outcome</phrase><phrase role="special">()</phrase></code>,
though, we can readily recast the interface function to deliver the first
<emphasis>successful</emphasis> result.
</para>
<para>
That does beg the question: what if <emphasis>all</emphasis> the task functions
throw an exception? In that case we'd probably better know about it.
</para>
<para>
<anchor id="exception_list"/>The <ulink url="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/n4407.html#parallel.exceptions.synopsis">C++
Parallelism Draft Technical Specification</ulink> proposes a <code><phrase
role="identifier">std</phrase><phrase role="special">::</phrase><phrase
role="identifier">exception_list</phrase></code> exception capable of delivering
a collection of <code><phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase
role="identifier">exception_ptr</phrase></code>s. Until that becomes universally
available, let's fake up an <code><phrase role="identifier">exception_list</phrase></code>
of our own:
</para>
<para>
<programlisting><phrase role="keyword">class</phrase> <phrase role="identifier">exception_list</phrase> <phrase role="special">:</phrase> <phrase role="keyword">public</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">runtime_error</phrase> <phrase role="special">{</phrase>
<phrase role="keyword">public</phrase><phrase role="special">:</phrase>
<phrase role="identifier">exception_list</phrase><phrase role="special">(</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">string</phrase> <phrase role="keyword">const</phrase><phrase role="special">&amp;</phrase> <phrase role="identifier">what</phrase><phrase role="special">)</phrase> <phrase role="special">:</phrase>
<phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">runtime_error</phrase><phrase role="special">(</phrase> <phrase role="identifier">what</phrase><phrase role="special">)</phrase> <phrase role="special">{</phrase>
<phrase role="special">}</phrase>
<phrase role="keyword">typedef</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">vector</phrase><phrase role="special">&lt;</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">exception_ptr</phrase> <phrase role="special">&gt;</phrase> <phrase role="identifier">bundle_t</phrase><phrase role="special">;</phrase>
<phrase role="comment">// N4407 proposed std::exception_list API</phrase>
<phrase role="keyword">typedef</phrase> <phrase role="identifier">bundle_t</phrase><phrase role="special">::</phrase><phrase role="identifier">const_iterator</phrase> <phrase role="identifier">iterator</phrase><phrase role="special">;</phrase>
<phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">size_t</phrase> <phrase role="identifier">size</phrase><phrase role="special">()</phrase> <phrase role="keyword">const</phrase> <phrase role="keyword">noexcept</phrase> <phrase role="special">{</phrase>
<phrase role="keyword">return</phrase> <phrase role="identifier">bundle_</phrase><phrase role="special">.</phrase><phrase role="identifier">size</phrase><phrase role="special">();</phrase>
<phrase role="special">}</phrase>
<phrase role="identifier">iterator</phrase> <phrase role="identifier">begin</phrase><phrase role="special">()</phrase> <phrase role="keyword">const</phrase> <phrase role="keyword">noexcept</phrase> <phrase role="special">{</phrase>
<phrase role="keyword">return</phrase> <phrase role="identifier">bundle_</phrase><phrase role="special">.</phrase><phrase role="identifier">begin</phrase><phrase role="special">();</phrase>
<phrase role="special">}</phrase>
<phrase role="identifier">iterator</phrase> <phrase role="identifier">end</phrase><phrase role="special">()</phrase> <phrase role="keyword">const</phrase> <phrase role="keyword">noexcept</phrase> <phrase role="special">{</phrase>
<phrase role="keyword">return</phrase> <phrase role="identifier">bundle_</phrase><phrase role="special">.</phrase><phrase role="identifier">end</phrase><phrase role="special">();</phrase>
<phrase role="special">}</phrase>
<phrase role="comment">// extension to populate</phrase>
<phrase role="keyword">void</phrase> <phrase role="identifier">add</phrase><phrase role="special">(</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">exception_ptr</phrase> <phrase role="identifier">ep</phrase><phrase role="special">)</phrase> <phrase role="special">{</phrase>
<phrase role="identifier">bundle_</phrase><phrase role="special">.</phrase><phrase role="identifier">push_back</phrase><phrase role="special">(</phrase> <phrase role="identifier">ep</phrase><phrase role="special">);</phrase>
<phrase role="special">}</phrase>
<phrase role="keyword">private</phrase><phrase role="special">:</phrase>
<phrase role="identifier">bundle_t</phrase> <phrase role="identifier">bundle_</phrase><phrase role="special">;</phrase>
<phrase role="special">};</phrase>
</programlisting>
</para>
<para>
Now we can build <code><phrase role="identifier">wait_first_success</phrase><phrase
role="special">()</phrase></code>, using <link linkend="wait_first_outcome_impl"><code><phrase
role="identifier">wait_first_outcome_impl</phrase><phrase role="special">()</phrase></code></link>.
</para>
<para>
Instead of retrieving only the first <code><phrase role="identifier">future</phrase><phrase
role="special">&lt;&gt;</phrase></code> from the queue, we must now loop
over <code><phrase role="identifier">future</phrase><phrase role="special">&lt;&gt;</phrase></code>
items. Of course we must limit that iteration! If we launch only <code><phrase
role="identifier">count</phrase></code> producer fibers, the <code><phrase
role="special">(</phrase><phrase role="identifier">count</phrase><phrase
role="special">+</phrase><phrase role="number">1</phrase><phrase role="special">)</phrase></code><superscript>st</superscript>
<link linkend="buffered_channel_pop"><code>buffered_channel::pop()</code></link> call
would block forever.
</para>
<para>
Given a ready <code><phrase role="identifier">future</phrase><phrase role="special">&lt;&gt;</phrase></code>,
we can distinguish failure by calling <link linkend="future_get_exception_ptr"><code>future::get_exception_ptr()</code></link>.
If the <code><phrase role="identifier">future</phrase><phrase role="special">&lt;&gt;</phrase></code>
in fact contains a result rather than an exception, <code><phrase role="identifier">get_exception_ptr</phrase><phrase
role="special">()</phrase></code> returns <code><phrase role="keyword">nullptr</phrase></code>.
In that case, we can confidently call <link linkend="future_get"><code>future::get()</code></link> to return
that result to our caller.
</para>
<para>
If the <code><phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase
role="identifier">exception_ptr</phrase></code> is <emphasis>not</emphasis>
<code><phrase role="keyword">nullptr</phrase></code>, though, we collect
it into our pending <code><phrase role="identifier">exception_list</phrase></code>
and loop back for the next <code><phrase role="identifier">future</phrase><phrase
role="special">&lt;&gt;</phrase></code> from the queue.
</para>
<para>
If we fall out of the loop &mdash; if every single task fiber threw an exception
&mdash; we throw the <code><phrase role="identifier">exception_list</phrase></code>
exception into which we've been collecting those <code><phrase role="identifier">std</phrase><phrase
role="special">::</phrase><phrase role="identifier">exception_ptr</phrase></code>s.
</para>
<para>
<anchor id="wait_first_success"/>
<programlisting><phrase role="keyword">template</phrase><phrase role="special">&lt;</phrase> <phrase role="keyword">typename</phrase> <phrase role="identifier">Fn</phrase><phrase role="special">,</phrase> <phrase role="keyword">typename</phrase> <phrase role="special">...</phrase> <phrase role="identifier">Fns</phrase> <phrase role="special">&gt;</phrase>
<phrase role="keyword">typename</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">result_of</phrase><phrase role="special">&lt;</phrase> <phrase role="identifier">Fn</phrase><phrase role="special">()</phrase> <phrase role="special">&gt;::</phrase><phrase role="identifier">type</phrase>
<phrase role="identifier">wait_first_success</phrase><phrase role="special">(</phrase> <phrase role="identifier">Fn</phrase> <phrase role="special">&amp;&amp;</phrase> <phrase role="identifier">function</phrase><phrase role="special">,</phrase> <phrase role="identifier">Fns</phrase> <phrase role="special">&amp;&amp;</phrase> <phrase role="special">...</phrase> <phrase role="identifier">functions</phrase><phrase role="special">)</phrase> <phrase role="special">{</phrase>
<phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">size_t</phrase> <phrase role="identifier">count</phrase><phrase role="special">(</phrase> <phrase role="number">1</phrase> <phrase role="special">+</phrase> <phrase role="keyword">sizeof</phrase> <phrase role="special">...</phrase> <phrase role="special">(</phrase> <phrase role="identifier">functions</phrase><phrase role="special">)</phrase> <phrase role="special">);</phrase>
<phrase role="comment">// In this case, the value we pass through the channel is actually a</phrase>
<phrase role="comment">// future -- which is already ready. future can carry either a value or an</phrase>
<phrase role="comment">// exception.</phrase>
<phrase role="keyword">typedef</phrase> <phrase role="keyword">typename</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">result_of</phrase><phrase role="special">&lt;</phrase> <phrase role="keyword">typename</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">decay</phrase><phrase role="special">&lt;</phrase> <phrase role="identifier">Fn</phrase> <phrase role="special">&gt;::</phrase><phrase role="identifier">type</phrase><phrase role="special">()</phrase> <phrase role="special">&gt;::</phrase><phrase role="identifier">type</phrase> <phrase role="identifier">return_t</phrase><phrase role="special">;</phrase>
<phrase role="keyword">typedef</phrase> <phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">fibers</phrase><phrase role="special">::</phrase><phrase role="identifier">future</phrase><phrase role="special">&lt;</phrase> <phrase role="identifier">return_t</phrase> <phrase role="special">&gt;</phrase> <phrase role="identifier">future_t</phrase><phrase role="special">;</phrase>
<phrase role="keyword">typedef</phrase> <phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">fibers</phrase><phrase role="special">::</phrase><phrase role="identifier">buffered_channel</phrase><phrase role="special">&lt;</phrase> <phrase role="identifier">future_t</phrase> <phrase role="special">&gt;</phrase> <phrase role="identifier">channel_t</phrase><phrase role="special">;</phrase>
<phrase role="keyword">auto</phrase> <phrase role="identifier">chanp</phrase><phrase role="special">(</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">make_shared</phrase><phrase role="special">&lt;</phrase> <phrase role="identifier">channel_t</phrase> <phrase role="special">&gt;(</phrase> <phrase role="number">64</phrase><phrase role="special">)</phrase> <phrase role="special">);</phrase>
<phrase role="comment">// launch all the relevant fibers</phrase>
<phrase role="identifier">wait_first_outcome_impl</phrase><phrase role="special">&lt;</phrase> <phrase role="identifier">return_t</phrase> <phrase role="special">&gt;(</phrase> <phrase role="identifier">chanp</phrase><phrase role="special">,</phrase>
<phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">forward</phrase><phrase role="special">&lt;</phrase> <phrase role="identifier">Fn</phrase> <phrase role="special">&gt;(</phrase> <phrase role="identifier">function</phrase><phrase role="special">),</phrase>
<phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">forward</phrase><phrase role="special">&lt;</phrase> <phrase role="identifier">Fns</phrase> <phrase role="special">&gt;(</phrase> <phrase role="identifier">functions</phrase><phrase role="special">)</phrase> <phrase role="special">...</phrase> <phrase role="special">);</phrase>
<phrase role="comment">// instantiate exception_list, just in case</phrase>
<phrase role="identifier">exception_list</phrase> <phrase role="identifier">exceptions</phrase><phrase role="special">(</phrase><phrase role="string">&quot;wait_first_success() produced only errors&quot;</phrase><phrase role="special">);</phrase>
<phrase role="comment">// retrieve up to 'count' results -- but stop there!</phrase>
<phrase role="keyword">for</phrase> <phrase role="special">(</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">size_t</phrase> <phrase role="identifier">i</phrase> <phrase role="special">=</phrase> <phrase role="number">0</phrase><phrase role="special">;</phrase> <phrase role="identifier">i</phrase> <phrase role="special">&lt;</phrase> <phrase role="identifier">count</phrase><phrase role="special">;</phrase> <phrase role="special">++</phrase><phrase role="identifier">i</phrase><phrase role="special">)</phrase> <phrase role="special">{</phrase>
<phrase role="comment">// retrieve the next future</phrase>
<phrase role="identifier">future_t</phrase> <phrase role="identifier">future</phrase><phrase role="special">(</phrase> <phrase role="identifier">chanp</phrase><phrase role="special">-&gt;</phrase><phrase role="identifier">value_pop</phrase><phrase role="special">()</phrase> <phrase role="special">);</phrase>
<phrase role="comment">// retrieve exception_ptr if any</phrase>
<phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">exception_ptr</phrase> <phrase role="identifier">error</phrase><phrase role="special">(</phrase> <phrase role="identifier">future</phrase><phrase role="special">.</phrase><phrase role="identifier">get_exception_ptr</phrase><phrase role="special">()</phrase> <phrase role="special">);</phrase>
<phrase role="comment">// if no error, then yay, return value</phrase>
<phrase role="keyword">if</phrase> <phrase role="special">(</phrase> <phrase role="special">!</phrase> <phrase role="identifier">error</phrase><phrase role="special">)</phrase> <phrase role="special">{</phrase>
<phrase role="comment">// close the channel: no subsequent push() has to succeed</phrase>
<phrase role="identifier">chanp</phrase><phrase role="special">-&gt;</phrase><phrase role="identifier">close</phrase><phrase role="special">();</phrase>
<phrase role="comment">// show caller the value we got</phrase>
<phrase role="keyword">return</phrase> <phrase role="identifier">future</phrase><phrase role="special">.</phrase><phrase role="identifier">get</phrase><phrase role="special">();</phrase>
<phrase role="special">}</phrase>
<phrase role="comment">// error is non-null: collect</phrase>
<phrase role="identifier">exceptions</phrase><phrase role="special">.</phrase><phrase role="identifier">add</phrase><phrase role="special">(</phrase> <phrase role="identifier">error</phrase><phrase role="special">);</phrase>
<phrase role="special">}</phrase>
<phrase role="comment">// We only arrive here when every passed function threw an exception.</phrase>
<phrase role="comment">// Throw our collection to inform caller.</phrase>
<phrase role="keyword">throw</phrase> <phrase role="identifier">exceptions</phrase><phrase role="special">;</phrase>
<phrase role="special">}</phrase>
</programlisting>
</para>
<para>
A call might look like this:
</para>
<para>
<programlisting><phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">string</phrase> <phrase role="identifier">result</phrase> <phrase role="special">=</phrase> <phrase role="identifier">wait_first_success</phrase><phrase role="special">(</phrase>
<phrase role="special">[](){</phrase> <phrase role="keyword">return</phrase> <phrase role="identifier">sleeper</phrase><phrase role="special">(</phrase><phrase role="string">&quot;wfss_first&quot;</phrase><phrase role="special">,</phrase> <phrase role="number">50</phrase><phrase role="special">,</phrase> <phrase role="keyword">true</phrase><phrase role="special">);</phrase> <phrase role="special">},</phrase>
<phrase role="special">[](){</phrase> <phrase role="keyword">return</phrase> <phrase role="identifier">sleeper</phrase><phrase role="special">(</phrase><phrase role="string">&quot;wfss_second&quot;</phrase><phrase role="special">,</phrase> <phrase role="number">100</phrase><phrase role="special">);</phrase> <phrase role="special">},</phrase>
<phrase role="special">[](){</phrase> <phrase role="keyword">return</phrase> <phrase role="identifier">sleeper</phrase><phrase role="special">(</phrase><phrase role="string">&quot;wfss_third&quot;</phrase><phrase role="special">,</phrase> <phrase role="number">150</phrase><phrase role="special">);</phrase> <phrase role="special">});</phrase>
<phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">cout</phrase> <phrase role="special">&lt;&lt;</phrase> <phrase role="string">&quot;wait_first_success(success) =&gt; &quot;</phrase> <phrase role="special">&lt;&lt;</phrase> <phrase role="identifier">result</phrase> <phrase role="special">&lt;&lt;</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">endl</phrase><phrase role="special">;</phrase>
<phrase role="identifier">assert</phrase><phrase role="special">(</phrase><phrase role="identifier">result</phrase> <phrase role="special">==</phrase> <phrase role="string">&quot;wfss_second&quot;</phrase><phrase role="special">);</phrase>
</programlisting>
</para>
</section>
<section id="fiber.when_any.when_any.when_any__heterogeneous_types">
<title><link linkend="fiber.when_any.when_any.when_any__heterogeneous_types">when_any,
heterogeneous types</link></title>
<para>
We would be remiss to ignore the case in which the various task functions
have distinct return types. That means that the value returned by the first
of them might have any one of those types. We can express that with <ulink
url="http://www.boost.org/doc/libs/release/doc/html/variant.html">Boost.Variant</ulink>.
</para>
<para>
To keep the example simple, we'll revert to pretending that none of them
can throw an exception. That makes <code><phrase role="identifier">wait_first_value_het</phrase><phrase
role="special">()</phrase></code> strongly resemble <link linkend="wait_first_value"><code><phrase
role="identifier">wait_first_value</phrase><phrase role="special">()</phrase></code></link>.
We can actually reuse <link linkend="wait_first_value_impl"><code><phrase
role="identifier">wait_first_value_impl</phrase><phrase role="special">()</phrase></code></link>,
merely passing <code><phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase
role="identifier">variant</phrase><phrase role="special">&lt;</phrase><phrase
role="identifier">T0</phrase><phrase role="special">,</phrase> <phrase
role="identifier">T1</phrase><phrase role="special">,</phrase> <phrase
role="special">...&gt;</phrase></code> as the queue's value type rather
than the common <code><phrase role="identifier">T</phrase></code>!
</para>
<para>
Naturally this could be extended to use <link linkend="wait_first_success"><code><phrase
role="identifier">wait_first_success</phrase><phrase role="special">()</phrase></code></link>
semantics instead.
</para>
<para>
<programlisting><phrase role="comment">// No need to break out the first Fn for interface function: let the compiler</phrase>
<phrase role="comment">// complain if empty.</phrase>
<phrase role="comment">// Our functions have different return types, and we might have to return any</phrase>
<phrase role="comment">// of them. Use a variant, expanding std::result_of&lt;Fn()&gt;::type for each Fn in</phrase>
<phrase role="comment">// parameter pack.</phrase>
<phrase role="keyword">template</phrase><phrase role="special">&lt;</phrase> <phrase role="keyword">typename</phrase> <phrase role="special">...</phrase> <phrase role="identifier">Fns</phrase> <phrase role="special">&gt;</phrase>
<phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">variant</phrase><phrase role="special">&lt;</phrase> <phrase role="keyword">typename</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">result_of</phrase><phrase role="special">&lt;</phrase> <phrase role="identifier">Fns</phrase><phrase role="special">()</phrase> <phrase role="special">&gt;::</phrase><phrase role="identifier">type</phrase> <phrase role="special">...</phrase> <phrase role="special">&gt;</phrase>
<phrase role="identifier">wait_first_value_het</phrase><phrase role="special">(</phrase> <phrase role="identifier">Fns</phrase> <phrase role="special">&amp;&amp;</phrase> <phrase role="special">...</phrase> <phrase role="identifier">functions</phrase><phrase role="special">)</phrase> <phrase role="special">{</phrase>
<phrase role="comment">// Use buffered_channel&lt;boost::variant&lt;T1, T2, ...&gt;&gt;; see remarks above.</phrase>
<phrase role="keyword">typedef</phrase> <phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">variant</phrase><phrase role="special">&lt;</phrase> <phrase role="keyword">typename</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">result_of</phrase><phrase role="special">&lt;</phrase> <phrase role="identifier">Fns</phrase><phrase role="special">()</phrase> <phrase role="special">&gt;::</phrase><phrase role="identifier">type</phrase> <phrase role="special">...</phrase> <phrase role="special">&gt;</phrase> <phrase role="identifier">return_t</phrase><phrase role="special">;</phrase>
<phrase role="keyword">typedef</phrase> <phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">fibers</phrase><phrase role="special">::</phrase><phrase role="identifier">buffered_channel</phrase><phrase role="special">&lt;</phrase> <phrase role="identifier">return_t</phrase> <phrase role="special">&gt;</phrase> <phrase role="identifier">channel_t</phrase><phrase role="special">;</phrase>
<phrase role="keyword">auto</phrase> <phrase role="identifier">chanp</phrase><phrase role="special">(</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">make_shared</phrase><phrase role="special">&lt;</phrase> <phrase role="identifier">channel_t</phrase> <phrase role="special">&gt;(</phrase> <phrase role="number">64</phrase><phrase role="special">)</phrase> <phrase role="special">);</phrase>
<phrase role="comment">// launch all the relevant fibers</phrase>
<phrase role="identifier">wait_first_value_impl</phrase><phrase role="special">&lt;</phrase> <phrase role="identifier">return_t</phrase> <phrase role="special">&gt;(</phrase> <phrase role="identifier">chanp</phrase><phrase role="special">,</phrase>
<phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">forward</phrase><phrase role="special">&lt;</phrase> <phrase role="identifier">Fns</phrase> <phrase role="special">&gt;(</phrase> <phrase role="identifier">functions</phrase><phrase role="special">)</phrase> <phrase role="special">...</phrase> <phrase role="special">);</phrase>
<phrase role="comment">// retrieve the first value</phrase>
<phrase role="identifier">return_t</phrase> <phrase role="identifier">value</phrase><phrase role="special">(</phrase> <phrase role="identifier">chanp</phrase><phrase role="special">-&gt;</phrase><phrase role="identifier">value_pop</phrase><phrase role="special">()</phrase> <phrase role="special">);</phrase>
<phrase role="comment">// close the channel: no subsequent push() has to succeed</phrase>
<phrase role="identifier">chanp</phrase><phrase role="special">-&gt;</phrase><phrase role="identifier">close</phrase><phrase role="special">();</phrase>
<phrase role="keyword">return</phrase> <phrase role="identifier">value</phrase><phrase role="special">;</phrase>
<phrase role="special">}</phrase>
</programlisting>
</para>
<para>
It might be called like this:
</para>
<para>
<programlisting><phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">variant</phrase><phrase role="special">&lt;</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">string</phrase><phrase role="special">,</phrase> <phrase role="keyword">double</phrase><phrase role="special">,</phrase> <phrase role="keyword">int</phrase> <phrase role="special">&gt;</phrase> <phrase role="identifier">result</phrase> <phrase role="special">=</phrase>
<phrase role="identifier">wait_first_value_het</phrase><phrase role="special">(</phrase>
<phrase role="special">[](){</phrase> <phrase role="keyword">return</phrase> <phrase role="identifier">sleeper</phrase><phrase role="special">(</phrase><phrase role="string">&quot;wfvh_third&quot;</phrase><phrase role="special">,</phrase> <phrase role="number">150</phrase><phrase role="special">);</phrase> <phrase role="special">},</phrase>
<phrase role="special">[](){</phrase> <phrase role="keyword">return</phrase> <phrase role="identifier">sleeper</phrase><phrase role="special">(</phrase><phrase role="number">3.14</phrase><phrase role="special">,</phrase> <phrase role="number">100</phrase><phrase role="special">);</phrase> <phrase role="special">},</phrase>
<phrase role="special">[](){</phrase> <phrase role="keyword">return</phrase> <phrase role="identifier">sleeper</phrase><phrase role="special">(</phrase><phrase role="number">17</phrase><phrase role="special">,</phrase> <phrase role="number">50</phrase><phrase role="special">);</phrase> <phrase role="special">});</phrase>
<phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">cout</phrase> <phrase role="special">&lt;&lt;</phrase> <phrase role="string">&quot;wait_first_value_het() =&gt; &quot;</phrase> <phrase role="special">&lt;&lt;</phrase> <phrase role="identifier">result</phrase> <phrase role="special">&lt;&lt;</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">endl</phrase><phrase role="special">;</phrase>
<phrase role="identifier">assert</phrase><phrase role="special">(</phrase><phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">get</phrase><phrase role="special">&lt;</phrase> <phrase role="keyword">int</phrase> <phrase role="special">&gt;(</phrase> <phrase role="identifier">result</phrase><phrase role="special">)</phrase> <phrase role="special">==</phrase> <phrase role="number">17</phrase><phrase role="special">);</phrase>
</programlisting>
</para>
</section>
<section id="fiber.when_any.when_any.when_any__a_dubious_alternative">
<title><link linkend="fiber.when_any.when_any.when_any__a_dubious_alternative">when_any,
a dubious alternative</link></title>
<para>
Certain topics in C++ can arouse strong passions, and exceptions are no
exception. We cannot resist mentioning &mdash; for purely informational purposes
&mdash; that when you need only the <emphasis>first</emphasis> result from some
number of concurrently-running fibers, it would be possible to pass a
<literal>shared_ptr&lt;<link linkend="class_promise"><code>promise&lt;&gt;</code></link>&gt;</literal> to the
participating fibers, then cause the initiating fiber to call <link linkend="future_get"><code>future::get()</code></link> on
its <link linkend="class_future"><code>future&lt;&gt;</code></link>. The first fiber to call <link linkend="promise_set_value"><code>promise::set_value()</code></link> on
that shared <code><phrase role="identifier">promise</phrase></code> will
succeed; subsequent <code><phrase role="identifier">set_value</phrase><phrase
role="special">()</phrase></code> calls on the same <code><phrase role="identifier">promise</phrase></code>
instance will throw <code><phrase role="identifier">future_error</phrase></code>.
</para>
<para>
Use this information at your own discretion. Beware the dark side.
</para>
</section>
</section>
<section id="fiber.when_any.when_all_functionality">
<title><link linkend="fiber.when_any.when_all_functionality">when_all functionality</link></title>
<section id="fiber.when_any.when_all_functionality.when_all__simple_completion">
<title><link linkend="fiber.when_any.when_all_functionality.when_all__simple_completion">when_all,
simple completion</link></title>
<para>
For the case in which we must wait for <emphasis>all</emphasis> task functions
to complete &mdash; but we don't need results (or expect exceptions) from any of
them &mdash; we can write <code><phrase role="identifier">wait_all_simple</phrase><phrase
role="special">()</phrase></code> that looks remarkably like <link linkend="wait_first_simple"><code><phrase
role="identifier">wait_first_simple</phrase><phrase role="special">()</phrase></code></link>.
The difference is that instead of our <link linkend="wait_done"><code><phrase
role="identifier">Done</phrase></code></link> class, we instantiate a <link linkend="class_barrier"><code>barrier</code></link> and
call its <link linkend="barrier_wait"><code>barrier::wait()</code></link>.
</para>
<para>
We initialize the <code><phrase role="identifier">barrier</phrase></code>
with <code><phrase role="special">(</phrase><phrase role="identifier">count</phrase><phrase
role="special">+</phrase><phrase role="number">1</phrase><phrase role="special">)</phrase></code>
because we are launching <code><phrase role="identifier">count</phrase></code>
fibers, plus the <code><phrase role="identifier">wait</phrase><phrase role="special">()</phrase></code>
call within <code><phrase role="identifier">wait_all_simple</phrase><phrase
role="special">()</phrase></code> itself.
</para>
<para>
<programlisting><phrase role="keyword">template</phrase><phrase role="special">&lt;</phrase> <phrase role="keyword">typename</phrase> <phrase role="special">...</phrase> <phrase role="identifier">Fns</phrase> <phrase role="special">&gt;</phrase>
<phrase role="keyword">void</phrase> <phrase role="identifier">wait_all_simple</phrase><phrase role="special">(</phrase> <phrase role="identifier">Fns</phrase> <phrase role="special">&amp;&amp;</phrase> <phrase role="special">...</phrase> <phrase role="identifier">functions</phrase><phrase role="special">)</phrase> <phrase role="special">{</phrase>
<phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">size_t</phrase> <phrase role="identifier">count</phrase><phrase role="special">(</phrase> <phrase role="keyword">sizeof</phrase> <phrase role="special">...</phrase> <phrase role="special">(</phrase> <phrase role="identifier">functions</phrase><phrase role="special">)</phrase> <phrase role="special">);</phrase>
<phrase role="comment">// Initialize a barrier(count+1) because we'll immediately wait on it. We</phrase>
<phrase role="comment">// don't want to wake up until 'count' more fibers wait on it. Even though</phrase>
<phrase role="comment">// we'll stick around until the last of them completes, use shared_ptr</phrase>
<phrase role="comment">// anyway because it's easier to be confident about lifespan issues.</phrase>
<phrase role="keyword">auto</phrase> <phrase role="identifier">barrier</phrase><phrase role="special">(</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">make_shared</phrase><phrase role="special">&lt;</phrase> <phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">fibers</phrase><phrase role="special">::</phrase><phrase role="identifier">barrier</phrase> <phrase role="special">&gt;(</phrase> <phrase role="identifier">count</phrase> <phrase role="special">+</phrase> <phrase role="number">1</phrase><phrase role="special">)</phrase> <phrase role="special">);</phrase>
<phrase role="identifier">wait_all_simple_impl</phrase><phrase role="special">(</phrase> <phrase role="identifier">barrier</phrase><phrase role="special">,</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">forward</phrase><phrase role="special">&lt;</phrase> <phrase role="identifier">Fns</phrase> <phrase role="special">&gt;(</phrase> <phrase role="identifier">functions</phrase><phrase role="special">)</phrase> <phrase role="special">...</phrase> <phrase role="special">);</phrase>
<phrase role="identifier">barrier</phrase><phrase role="special">-&gt;</phrase><phrase role="identifier">wait</phrase><phrase role="special">();</phrase>
<phrase role="special">}</phrase>
</programlisting>
</para>
<para>
As stated above, the only difference between <code><phrase role="identifier">wait_all_simple_impl</phrase><phrase
role="special">()</phrase></code> and <link linkend="wait_first_simple_impl"><code><phrase
role="identifier">wait_first_simple_impl</phrase><phrase role="special">()</phrase></code></link>
is that the former calls <code><phrase role="identifier">barrier</phrase><phrase
role="special">::</phrase><phrase role="identifier">wait</phrase><phrase
role="special">()</phrase></code> rather than <code><phrase role="identifier">Done</phrase><phrase
role="special">::</phrase><phrase role="identifier">notify</phrase><phrase
role="special">()</phrase></code>:
</para>
<para>
<programlisting><phrase role="keyword">template</phrase><phrase role="special">&lt;</phrase> <phrase role="keyword">typename</phrase> <phrase role="identifier">Fn</phrase><phrase role="special">,</phrase> <phrase role="keyword">typename</phrase> <phrase role="special">...</phrase> <phrase role="identifier">Fns</phrase> <phrase role="special">&gt;</phrase>
<phrase role="keyword">void</phrase> <phrase role="identifier">wait_all_simple_impl</phrase><phrase role="special">(</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">shared_ptr</phrase><phrase role="special">&lt;</phrase> <phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">fibers</phrase><phrase role="special">::</phrase><phrase role="identifier">barrier</phrase> <phrase role="special">&gt;</phrase> <phrase role="identifier">barrier</phrase><phrase role="special">,</phrase>
<phrase role="identifier">Fn</phrase> <phrase role="special">&amp;&amp;</phrase> <phrase role="identifier">function</phrase><phrase role="special">,</phrase> <phrase role="identifier">Fns</phrase> <phrase role="special">&amp;&amp;</phrase> <phrase role="special">...</phrase> <phrase role="identifier">functions</phrase><phrase role="special">)</phrase> <phrase role="special">{</phrase>
<phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">fibers</phrase><phrase role="special">::</phrase><phrase role="identifier">fiber</phrase><phrase role="special">(</phrase>
<phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">bind</phrase><phrase role="special">(</phrase>
<phrase role="special">[](</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">shared_ptr</phrase><phrase role="special">&lt;</phrase> <phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">fibers</phrase><phrase role="special">::</phrase><phrase role="identifier">barrier</phrase> <phrase role="special">&gt;</phrase> <phrase role="special">&amp;</phrase> <phrase role="identifier">barrier</phrase><phrase role="special">,</phrase>
<phrase role="keyword">typename</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">decay</phrase><phrase role="special">&lt;</phrase> <phrase role="identifier">Fn</phrase> <phrase role="special">&gt;::</phrase><phrase role="identifier">type</phrase> <phrase role="special">&amp;</phrase> <phrase role="identifier">function</phrase><phrase role="special">)</phrase> <phrase role="keyword">mutable</phrase> <phrase role="special">{</phrase>
<phrase role="identifier">function</phrase><phrase role="special">();</phrase>
<phrase role="identifier">barrier</phrase><phrase role="special">-&gt;</phrase><phrase role="identifier">wait</phrase><phrase role="special">();</phrase>
<phrase role="special">},</phrase>
<phrase role="identifier">barrier</phrase><phrase role="special">,</phrase>
<phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">forward</phrase><phrase role="special">&lt;</phrase> <phrase role="identifier">Fn</phrase> <phrase role="special">&gt;(</phrase> <phrase role="identifier">function</phrase><phrase role="special">)</phrase>
<phrase role="special">)).</phrase><phrase role="identifier">detach</phrase><phrase role="special">();</phrase>
<phrase role="identifier">wait_all_simple_impl</phrase><phrase role="special">(</phrase> <phrase role="identifier">barrier</phrase><phrase role="special">,</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">forward</phrase><phrase role="special">&lt;</phrase> <phrase role="identifier">Fns</phrase> <phrase role="special">&gt;(</phrase> <phrase role="identifier">functions</phrase><phrase role="special">)</phrase> <phrase role="special">...</phrase> <phrase role="special">);</phrase>
<phrase role="special">}</phrase>
</programlisting>
</para>
<para>
You might call it like this:
</para>
<para>
<programlisting><phrase role="identifier">wait_all_simple</phrase><phrase role="special">(</phrase>
<phrase role="special">[](){</phrase> <phrase role="identifier">sleeper</phrase><phrase role="special">(</phrase><phrase role="string">&quot;was_long&quot;</phrase><phrase role="special">,</phrase> <phrase role="number">150</phrase><phrase role="special">);</phrase> <phrase role="special">},</phrase>
<phrase role="special">[](){</phrase> <phrase role="identifier">sleeper</phrase><phrase role="special">(</phrase><phrase role="string">&quot;was_medium&quot;</phrase><phrase role="special">,</phrase> <phrase role="number">100</phrase><phrase role="special">);</phrase> <phrase role="special">},</phrase>
<phrase role="special">[](){</phrase> <phrase role="identifier">sleeper</phrase><phrase role="special">(</phrase><phrase role="string">&quot;was_short&quot;</phrase><phrase role="special">,</phrase> <phrase role="number">50</phrase><phrase role="special">);</phrase> <phrase role="special">});</phrase>
</programlisting>
</para>
<para>
Control will not return from the <code><phrase role="identifier">wait_all_simple</phrase><phrase
role="special">()</phrase></code> call until the last of its task functions
has completed.
</para>
</section>
<section id="fiber.when_any.when_all_functionality.when_all__return_values">
<title><link linkend="fiber.when_any.when_all_functionality.when_all__return_values">when_all,
return values</link></title>
<para>
As soon as we want to collect return values from all the task functions,
we can see right away how to reuse <link linkend="wait_first_value"><code><phrase
role="identifier">wait_first_value</phrase><phrase role="special">()</phrase></code></link>'s
queue&lt;T&gt; for the purpose. All we have to do is avoid closing it after
the first value!
</para>
<para>
But in fact, collecting multiple values raises an interesting question:
do we <emphasis>really</emphasis> want to wait until the slowest of them
has arrived? Wouldn't we rather process each result as soon as it becomes
available?
</para>
<para>
Fortunately we can present both APIs. Let's define <code><phrase role="identifier">wait_all_values_source</phrase><phrase
role="special">()</phrase></code> to return <code><phrase role="identifier">shared_ptr</phrase><phrase
role="special">&lt;</phrase><phrase role="identifier">buffered_channel</phrase><phrase
role="special">&lt;</phrase><phrase role="identifier">T</phrase><phrase
role="special">&gt;&gt;</phrase></code>.
</para>
<para>
<anchor id="wait_all_values"/>Given <code><phrase role="identifier">wait_all_values_source</phrase><phrase
role="special">()</phrase></code>, it's straightforward to implement <code><phrase
role="identifier">wait_all_values</phrase><phrase role="special">()</phrase></code>:
</para>
<para>
<programlisting><phrase role="keyword">template</phrase><phrase role="special">&lt;</phrase> <phrase role="keyword">typename</phrase> <phrase role="identifier">Fn</phrase><phrase role="special">,</phrase> <phrase role="keyword">typename</phrase> <phrase role="special">...</phrase> <phrase role="identifier">Fns</phrase> <phrase role="special">&gt;</phrase>
<phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">vector</phrase><phrase role="special">&lt;</phrase> <phrase role="keyword">typename</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">result_of</phrase><phrase role="special">&lt;</phrase> <phrase role="identifier">Fn</phrase><phrase role="special">()</phrase> <phrase role="special">&gt;::</phrase><phrase role="identifier">type</phrase> <phrase role="special">&gt;</phrase>
<phrase role="identifier">wait_all_values</phrase><phrase role="special">(</phrase> <phrase role="identifier">Fn</phrase> <phrase role="special">&amp;&amp;</phrase> <phrase role="identifier">function</phrase><phrase role="special">,</phrase> <phrase role="identifier">Fns</phrase> <phrase role="special">&amp;&amp;</phrase> <phrase role="special">...</phrase> <phrase role="identifier">functions</phrase><phrase role="special">)</phrase> <phrase role="special">{</phrase>
<phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">size_t</phrase> <phrase role="identifier">count</phrase><phrase role="special">(</phrase> <phrase role="number">1</phrase> <phrase role="special">+</phrase> <phrase role="keyword">sizeof</phrase> <phrase role="special">...</phrase> <phrase role="special">(</phrase> <phrase role="identifier">functions</phrase><phrase role="special">)</phrase> <phrase role="special">);</phrase>
<phrase role="keyword">typedef</phrase> <phrase role="keyword">typename</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">result_of</phrase><phrase role="special">&lt;</phrase> <phrase role="identifier">Fn</phrase><phrase role="special">()</phrase> <phrase role="special">&gt;::</phrase><phrase role="identifier">type</phrase> <phrase role="identifier">return_t</phrase><phrase role="special">;</phrase>
<phrase role="keyword">typedef</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">vector</phrase><phrase role="special">&lt;</phrase> <phrase role="identifier">return_t</phrase> <phrase role="special">&gt;</phrase> <phrase role="identifier">vector_t</phrase><phrase role="special">;</phrase>
<phrase role="identifier">vector_t</phrase> <phrase role="identifier">results</phrase><phrase role="special">;</phrase>
<phrase role="identifier">results</phrase><phrase role="special">.</phrase><phrase role="identifier">reserve</phrase><phrase role="special">(</phrase> <phrase role="identifier">count</phrase><phrase role="special">);</phrase>
<phrase role="comment">// get channel</phrase>
<phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">shared_ptr</phrase><phrase role="special">&lt;</phrase> <phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">fibers</phrase><phrase role="special">::</phrase><phrase role="identifier">buffered_channel</phrase><phrase role="special">&lt;</phrase> <phrase role="identifier">return_t</phrase> <phrase role="special">&gt;</phrase> <phrase role="special">&gt;</phrase> <phrase role="identifier">chan</phrase> <phrase role="special">=</phrase>
<phrase role="identifier">wait_all_values_source</phrase><phrase role="special">(</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">forward</phrase><phrase role="special">&lt;</phrase> <phrase role="identifier">Fn</phrase> <phrase role="special">&gt;(</phrase> <phrase role="identifier">function</phrase><phrase role="special">),</phrase>
<phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">forward</phrase><phrase role="special">&lt;</phrase> <phrase role="identifier">Fns</phrase> <phrase role="special">&gt;(</phrase> <phrase role="identifier">functions</phrase><phrase role="special">)</phrase> <phrase role="special">...</phrase> <phrase role="special">);</phrase>
<phrase role="comment">// fill results vector</phrase>
<phrase role="identifier">return_t</phrase> <phrase role="identifier">value</phrase><phrase role="special">;</phrase>
<phrase role="keyword">while</phrase> <phrase role="special">(</phrase> <phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">fibers</phrase><phrase role="special">::</phrase><phrase role="identifier">channel_op_status</phrase><phrase role="special">::</phrase><phrase role="identifier">success</phrase> <phrase role="special">==</phrase> <phrase role="identifier">chan</phrase><phrase role="special">-&gt;</phrase><phrase role="identifier">pop</phrase><phrase role="special">(</phrase><phrase role="identifier">value</phrase><phrase role="special">)</phrase> <phrase role="special">)</phrase> <phrase role="special">{</phrase>
<phrase role="identifier">results</phrase><phrase role="special">.</phrase><phrase role="identifier">push_back</phrase><phrase role="special">(</phrase> <phrase role="identifier">value</phrase><phrase role="special">);</phrase>
<phrase role="special">}</phrase>
<phrase role="comment">// return vector to caller</phrase>
<phrase role="keyword">return</phrase> <phrase role="identifier">results</phrase><phrase role="special">;</phrase>
<phrase role="special">}</phrase>
</programlisting>
</para>
<para>
It might be called like this:
</para>
<para>
<programlisting><phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">vector</phrase><phrase role="special">&lt;</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">string</phrase> <phrase role="special">&gt;</phrase> <phrase role="identifier">values</phrase> <phrase role="special">=</phrase>
<phrase role="identifier">wait_all_values</phrase><phrase role="special">(</phrase>
<phrase role="special">[](){</phrase> <phrase role="keyword">return</phrase> <phrase role="identifier">sleeper</phrase><phrase role="special">(</phrase><phrase role="string">&quot;wav_late&quot;</phrase><phrase role="special">,</phrase> <phrase role="number">150</phrase><phrase role="special">);</phrase> <phrase role="special">},</phrase>
<phrase role="special">[](){</phrase> <phrase role="keyword">return</phrase> <phrase role="identifier">sleeper</phrase><phrase role="special">(</phrase><phrase role="string">&quot;wav_middle&quot;</phrase><phrase role="special">,</phrase> <phrase role="number">100</phrase><phrase role="special">);</phrase> <phrase role="special">},</phrase>
<phrase role="special">[](){</phrase> <phrase role="keyword">return</phrase> <phrase role="identifier">sleeper</phrase><phrase role="special">(</phrase><phrase role="string">&quot;wav_early&quot;</phrase><phrase role="special">,</phrase> <phrase role="number">50</phrase><phrase role="special">);</phrase> <phrase role="special">});</phrase>
</programlisting>
</para>
<para>
As you can see from the loop in <code><phrase role="identifier">wait_all_values</phrase><phrase
role="special">()</phrase></code>, instead of requiring its caller to count
values, we define <code><phrase role="identifier">wait_all_values_source</phrase><phrase
role="special">()</phrase></code> to <link linkend="buffered_channel_close"><code>buffered_channel::close()</code></link> the
queue when done. But how do we do that? Each producer fiber is independent.
It has no idea whether it is the last one to <link linkend="buffered_channel_push"><code>buffered_channel::push()</code></link> a
value.
</para>
<para>
<anchor id="wait_nqueue"/>We can address that problem with a counting façade
for the <code><phrase role="identifier">queue</phrase><phrase role="special">&lt;&gt;</phrase></code>.
In fact, our façade need only support the producer end of the queue.
</para>
<para>
[wait_nqueue]
</para>
<para>
<anchor id="wait_all_values_source"/>Armed with <code><phrase role="identifier">nqueue</phrase><phrase
role="special">&lt;&gt;</phrase></code>, we can implement <code><phrase
role="identifier">wait_all_values_source</phrase><phrase role="special">()</phrase></code>.
It starts just like <link linkend="wait_first_value"><code><phrase role="identifier">wait_first_value</phrase><phrase
role="special">()</phrase></code></link>. The difference is that we wrap
the <code><phrase role="identifier">queue</phrase><phrase role="special">&lt;</phrase><phrase
role="identifier">T</phrase><phrase role="special">&gt;</phrase></code>
with an <code><phrase role="identifier">nqueue</phrase><phrase role="special">&lt;</phrase><phrase
role="identifier">T</phrase><phrase role="special">&gt;</phrase></code>
to pass to the producer fibers.
</para>
<para>
Then, of course, instead of popping the first value, closing the queue
and returning it, we simply return the <code><phrase role="identifier">shared_ptr</phrase><phrase
role="special">&lt;</phrase><phrase role="identifier">queue</phrase><phrase
role="special">&lt;</phrase><phrase role="identifier">T</phrase><phrase
role="special">&gt;&gt;</phrase></code>.
</para>
<para>
<programlisting><phrase role="comment">// Return a shared_ptr&lt;buffered_channel&lt;T&gt;&gt; from which the caller can</phrase>
<phrase role="comment">// retrieve each new result as it arrives, until 'closed'.</phrase>
<phrase role="keyword">template</phrase><phrase role="special">&lt;</phrase> <phrase role="keyword">typename</phrase> <phrase role="identifier">Fn</phrase><phrase role="special">,</phrase> <phrase role="keyword">typename</phrase> <phrase role="special">...</phrase> <phrase role="identifier">Fns</phrase> <phrase role="special">&gt;</phrase>
<phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">shared_ptr</phrase><phrase role="special">&lt;</phrase> <phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">fibers</phrase><phrase role="special">::</phrase><phrase role="identifier">buffered_channel</phrase><phrase role="special">&lt;</phrase> <phrase role="keyword">typename</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">result_of</phrase><phrase role="special">&lt;</phrase> <phrase role="identifier">Fn</phrase><phrase role="special">()</phrase> <phrase role="special">&gt;::</phrase><phrase role="identifier">type</phrase> <phrase role="special">&gt;</phrase> <phrase role="special">&gt;</phrase>
<phrase role="identifier">wait_all_values_source</phrase><phrase role="special">(</phrase> <phrase role="identifier">Fn</phrase> <phrase role="special">&amp;&amp;</phrase> <phrase role="identifier">function</phrase><phrase role="special">,</phrase> <phrase role="identifier">Fns</phrase> <phrase role="special">&amp;&amp;</phrase> <phrase role="special">...</phrase> <phrase role="identifier">functions</phrase><phrase role="special">)</phrase> <phrase role="special">{</phrase>
<phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">size_t</phrase> <phrase role="identifier">count</phrase><phrase role="special">(</phrase> <phrase role="number">1</phrase> <phrase role="special">+</phrase> <phrase role="keyword">sizeof</phrase> <phrase role="special">...</phrase> <phrase role="special">(</phrase> <phrase role="identifier">functions</phrase><phrase role="special">)</phrase> <phrase role="special">);</phrase>
<phrase role="keyword">typedef</phrase> <phrase role="keyword">typename</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">result_of</phrase><phrase role="special">&lt;</phrase> <phrase role="identifier">Fn</phrase><phrase role="special">()</phrase> <phrase role="special">&gt;::</phrase><phrase role="identifier">type</phrase> <phrase role="identifier">return_t</phrase><phrase role="special">;</phrase>
<phrase role="keyword">typedef</phrase> <phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">fibers</phrase><phrase role="special">::</phrase><phrase role="identifier">buffered_channel</phrase><phrase role="special">&lt;</phrase> <phrase role="identifier">return_t</phrase> <phrase role="special">&gt;</phrase> <phrase role="identifier">channel_t</phrase><phrase role="special">;</phrase>
<phrase role="comment">// make the channel</phrase>
<phrase role="keyword">auto</phrase> <phrase role="identifier">chanp</phrase><phrase role="special">(</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">make_shared</phrase><phrase role="special">&lt;</phrase> <phrase role="identifier">channel_t</phrase> <phrase role="special">&gt;(</phrase> <phrase role="number">64</phrase><phrase role="special">)</phrase> <phrase role="special">);</phrase>
<phrase role="comment">// and make an nchannel facade to close it after 'count' items</phrase>
<phrase role="keyword">auto</phrase> <phrase role="identifier">ncp</phrase><phrase role="special">(</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">make_shared</phrase><phrase role="special">&lt;</phrase> <phrase role="identifier">nchannel</phrase><phrase role="special">&lt;</phrase> <phrase role="identifier">return_t</phrase> <phrase role="special">&gt;</phrase> <phrase role="special">&gt;(</phrase> <phrase role="identifier">chanp</phrase><phrase role="special">,</phrase> <phrase role="identifier">count</phrase><phrase role="special">)</phrase> <phrase role="special">);</phrase>
<phrase role="comment">// pass that nchannel facade to all the relevant fibers</phrase>
<phrase role="identifier">wait_all_values_impl</phrase><phrase role="special">&lt;</phrase> <phrase role="identifier">return_t</phrase> <phrase role="special">&gt;(</phrase> <phrase role="identifier">ncp</phrase><phrase role="special">,</phrase>
<phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">forward</phrase><phrase role="special">&lt;</phrase> <phrase role="identifier">Fn</phrase> <phrase role="special">&gt;(</phrase> <phrase role="identifier">function</phrase><phrase role="special">),</phrase>
<phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">forward</phrase><phrase role="special">&lt;</phrase> <phrase role="identifier">Fns</phrase> <phrase role="special">&gt;(</phrase> <phrase role="identifier">functions</phrase><phrase role="special">)</phrase> <phrase role="special">...</phrase> <phrase role="special">);</phrase>
<phrase role="comment">// then return the channel for consumer</phrase>
<phrase role="keyword">return</phrase> <phrase role="identifier">chanp</phrase><phrase role="special">;</phrase>
<phrase role="special">}</phrase>
</programlisting>
</para>
<para>
For example:
</para>
<para>
<programlisting><phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">shared_ptr</phrase><phrase role="special">&lt;</phrase> <phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">fibers</phrase><phrase role="special">::</phrase><phrase role="identifier">buffered_channel</phrase><phrase role="special">&lt;</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">string</phrase> <phrase role="special">&gt;</phrase> <phrase role="special">&gt;</phrase> <phrase role="identifier">chan</phrase> <phrase role="special">=</phrase>
<phrase role="identifier">wait_all_values_source</phrase><phrase role="special">(</phrase>
<phrase role="special">[](){</phrase> <phrase role="keyword">return</phrase> <phrase role="identifier">sleeper</phrase><phrase role="special">(</phrase><phrase role="string">&quot;wavs_third&quot;</phrase><phrase role="special">,</phrase> <phrase role="number">150</phrase><phrase role="special">);</phrase> <phrase role="special">},</phrase>
<phrase role="special">[](){</phrase> <phrase role="keyword">return</phrase> <phrase role="identifier">sleeper</phrase><phrase role="special">(</phrase><phrase role="string">&quot;wavs_second&quot;</phrase><phrase role="special">,</phrase> <phrase role="number">100</phrase><phrase role="special">);</phrase> <phrase role="special">},</phrase>
<phrase role="special">[](){</phrase> <phrase role="keyword">return</phrase> <phrase role="identifier">sleeper</phrase><phrase role="special">(</phrase><phrase role="string">&quot;wavs_first&quot;</phrase><phrase role="special">,</phrase> <phrase role="number">50</phrase><phrase role="special">);</phrase> <phrase role="special">});</phrase>
<phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">string</phrase> <phrase role="identifier">value</phrase><phrase role="special">;</phrase>
<phrase role="keyword">while</phrase> <phrase role="special">(</phrase> <phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">fibers</phrase><phrase role="special">::</phrase><phrase role="identifier">channel_op_status</phrase><phrase role="special">::</phrase><phrase role="identifier">success</phrase> <phrase role="special">==</phrase> <phrase role="identifier">chan</phrase><phrase role="special">-&gt;</phrase><phrase role="identifier">pop</phrase><phrase role="special">(</phrase><phrase role="identifier">value</phrase><phrase role="special">)</phrase> <phrase role="special">)</phrase> <phrase role="special">{</phrase>
<phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">cout</phrase> <phrase role="special">&lt;&lt;</phrase> <phrase role="string">&quot;wait_all_values_source() =&gt; '&quot;</phrase> <phrase role="special">&lt;&lt;</phrase> <phrase role="identifier">value</phrase>
<phrase role="special">&lt;&lt;</phrase> <phrase role="string">&quot;'&quot;</phrase> <phrase role="special">&lt;&lt;</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">endl</phrase><phrase role="special">;</phrase>
<phrase role="special">}</phrase>
</programlisting>
</para>
<para>
<anchor id="wait_all_values_impl"/><code><phrase role="identifier">wait_all_values_impl</phrase><phrase
role="special">()</phrase></code> really is just like <link linkend="wait_first_value_impl"><code><phrase
role="identifier">wait_first_value_impl</phrase><phrase role="special">()</phrase></code></link>
except for the use of <code><phrase role="identifier">nqueue</phrase><phrase
role="special">&lt;</phrase><phrase role="identifier">T</phrase><phrase
role="special">&gt;</phrase></code> rather than <code><phrase role="identifier">queue</phrase><phrase
role="special">&lt;</phrase><phrase role="identifier">T</phrase><phrase
role="special">&gt;</phrase></code>:
</para>
<para>
<programlisting><phrase role="keyword">template</phrase><phrase role="special">&lt;</phrase> <phrase role="keyword">typename</phrase> <phrase role="identifier">T</phrase><phrase role="special">,</phrase> <phrase role="keyword">typename</phrase> <phrase role="identifier">Fn</phrase> <phrase role="special">&gt;</phrase>
<phrase role="keyword">void</phrase> <phrase role="identifier">wait_all_values_impl</phrase><phrase role="special">(</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">shared_ptr</phrase><phrase role="special">&lt;</phrase> <phrase role="identifier">nchannel</phrase><phrase role="special">&lt;</phrase> <phrase role="identifier">T</phrase> <phrase role="special">&gt;</phrase> <phrase role="special">&gt;</phrase> <phrase role="identifier">chan</phrase><phrase role="special">,</phrase>
<phrase role="identifier">Fn</phrase> <phrase role="special">&amp;&amp;</phrase> <phrase role="identifier">function</phrase><phrase role="special">)</phrase> <phrase role="special">{</phrase>
<phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">fibers</phrase><phrase role="special">::</phrase><phrase role="identifier">fiber</phrase><phrase role="special">(</phrase> <phrase role="special">[</phrase><phrase role="identifier">chan</phrase><phrase role="special">,</phrase> <phrase role="identifier">function</phrase><phrase role="special">](){</phrase>
<phrase role="identifier">chan</phrase><phrase role="special">-&gt;</phrase><phrase role="identifier">push</phrase><phrase role="special">(</phrase><phrase role="identifier">function</phrase><phrase role="special">());</phrase>
<phrase role="special">}).</phrase><phrase role="identifier">detach</phrase><phrase role="special">();</phrase>
<phrase role="special">}</phrase>
</programlisting>
</para>
</section>
<section id="fiber.when_any.when_all_functionality.when_all_until_first_exception">
<title><link linkend="fiber.when_any.when_all_functionality.when_all_until_first_exception">when_all
until first exception</link></title>
<para>
Naturally, just as with <link linkend="wait_first_outcome"><code><phrase
role="identifier">wait_first_outcome</phrase><phrase role="special">()</phrase></code></link>,
we can elaborate <link linkend="wait_all_values"><code><phrase role="identifier">wait_all_values</phrase><phrase
role="special">()</phrase></code></link> and <link linkend="wait_all_values_source"><code><phrase
role="identifier">wait_all_values_source</phrase><phrase role="special">()</phrase></code></link>
by passing <code><phrase role="identifier">future</phrase><phrase role="special">&lt;</phrase>
<phrase role="identifier">T</phrase> <phrase role="special">&gt;</phrase></code>
instead of plain <code><phrase role="identifier">T</phrase></code>.
</para>
<para>
<anchor id="wait_all_until_error"/><code><phrase role="identifier">wait_all_until_error</phrase><phrase
role="special">()</phrase></code> pops that <code><phrase role="identifier">future</phrase><phrase
role="special">&lt;</phrase> <phrase role="identifier">T</phrase> <phrase
role="special">&gt;</phrase></code> and calls its <link linkend="future_get"><code>future::get()</code></link>:
</para>
<para>
<programlisting><phrase role="keyword">template</phrase><phrase role="special">&lt;</phrase> <phrase role="keyword">typename</phrase> <phrase role="identifier">Fn</phrase><phrase role="special">,</phrase> <phrase role="keyword">typename</phrase> <phrase role="special">...</phrase> <phrase role="identifier">Fns</phrase> <phrase role="special">&gt;</phrase>
<phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">vector</phrase><phrase role="special">&lt;</phrase> <phrase role="keyword">typename</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">result_of</phrase><phrase role="special">&lt;</phrase> <phrase role="identifier">Fn</phrase><phrase role="special">()</phrase> <phrase role="special">&gt;::</phrase><phrase role="identifier">type</phrase> <phrase role="special">&gt;</phrase>
<phrase role="identifier">wait_all_until_error</phrase><phrase role="special">(</phrase> <phrase role="identifier">Fn</phrase> <phrase role="special">&amp;&amp;</phrase> <phrase role="identifier">function</phrase><phrase role="special">,</phrase> <phrase role="identifier">Fns</phrase> <phrase role="special">&amp;&amp;</phrase> <phrase role="special">...</phrase> <phrase role="identifier">functions</phrase><phrase role="special">)</phrase> <phrase role="special">{</phrase>
<phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">size_t</phrase> <phrase role="identifier">count</phrase><phrase role="special">(</phrase> <phrase role="number">1</phrase> <phrase role="special">+</phrase> <phrase role="keyword">sizeof</phrase> <phrase role="special">...</phrase> <phrase role="special">(</phrase> <phrase role="identifier">functions</phrase><phrase role="special">)</phrase> <phrase role="special">);</phrase>
<phrase role="keyword">typedef</phrase> <phrase role="keyword">typename</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">result_of</phrase><phrase role="special">&lt;</phrase> <phrase role="identifier">Fn</phrase><phrase role="special">()</phrase> <phrase role="special">&gt;::</phrase><phrase role="identifier">type</phrase> <phrase role="identifier">return_t</phrase><phrase role="special">;</phrase>
<phrase role="keyword">typedef</phrase> <phrase role="keyword">typename</phrase> <phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">fibers</phrase><phrase role="special">::</phrase><phrase role="identifier">future</phrase><phrase role="special">&lt;</phrase> <phrase role="identifier">return_t</phrase> <phrase role="special">&gt;</phrase> <phrase role="identifier">future_t</phrase><phrase role="special">;</phrase>
<phrase role="keyword">typedef</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">vector</phrase><phrase role="special">&lt;</phrase> <phrase role="identifier">return_t</phrase> <phrase role="special">&gt;</phrase> <phrase role="identifier">vector_t</phrase><phrase role="special">;</phrase>
<phrase role="identifier">vector_t</phrase> <phrase role="identifier">results</phrase><phrase role="special">;</phrase>
<phrase role="identifier">results</phrase><phrase role="special">.</phrase><phrase role="identifier">reserve</phrase><phrase role="special">(</phrase> <phrase role="identifier">count</phrase><phrase role="special">);</phrase>
<phrase role="comment">// get channel</phrase>
<phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">shared_ptr</phrase><phrase role="special">&lt;</phrase>
<phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">fibers</phrase><phrase role="special">::</phrase><phrase role="identifier">buffered_channel</phrase><phrase role="special">&lt;</phrase> <phrase role="identifier">future_t</phrase> <phrase role="special">&gt;</phrase> <phrase role="special">&gt;</phrase> <phrase role="identifier">chan</phrase><phrase role="special">(</phrase>
<phrase role="identifier">wait_all_until_error_source</phrase><phrase role="special">(</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">forward</phrase><phrase role="special">&lt;</phrase> <phrase role="identifier">Fn</phrase> <phrase role="special">&gt;(</phrase> <phrase role="identifier">function</phrase><phrase role="special">),</phrase>
<phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">forward</phrase><phrase role="special">&lt;</phrase> <phrase role="identifier">Fns</phrase> <phrase role="special">&gt;(</phrase> <phrase role="identifier">functions</phrase><phrase role="special">)</phrase> <phrase role="special">...</phrase> <phrase role="special">)</phrase> <phrase role="special">);</phrase>
<phrase role="comment">// fill results vector</phrase>
<phrase role="identifier">future_t</phrase> <phrase role="identifier">future</phrase><phrase role="special">;</phrase>
<phrase role="keyword">while</phrase> <phrase role="special">(</phrase> <phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">fibers</phrase><phrase role="special">::</phrase><phrase role="identifier">channel_op_status</phrase><phrase role="special">::</phrase><phrase role="identifier">success</phrase> <phrase role="special">==</phrase> <phrase role="identifier">chan</phrase><phrase role="special">-&gt;</phrase><phrase role="identifier">pop</phrase><phrase role="special">(</phrase> <phrase role="identifier">future</phrase><phrase role="special">)</phrase> <phrase role="special">)</phrase> <phrase role="special">{</phrase>
<phrase role="identifier">results</phrase><phrase role="special">.</phrase><phrase role="identifier">push_back</phrase><phrase role="special">(</phrase> <phrase role="identifier">future</phrase><phrase role="special">.</phrase><phrase role="identifier">get</phrase><phrase role="special">()</phrase> <phrase role="special">);</phrase>
<phrase role="special">}</phrase>
<phrase role="comment">// return vector to caller</phrase>
<phrase role="keyword">return</phrase> <phrase role="identifier">results</phrase><phrase role="special">;</phrase>
<phrase role="special">}</phrase>
</programlisting>
</para>
<para>
For example:
</para>
<para>
<programlisting><phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">string</phrase> <phrase role="identifier">thrown</phrase><phrase role="special">;</phrase>
<phrase role="keyword">try</phrase> <phrase role="special">{</phrase>
<phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">vector</phrase><phrase role="special">&lt;</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">string</phrase> <phrase role="special">&gt;</phrase> <phrase role="identifier">values</phrase> <phrase role="special">=</phrase> <phrase role="identifier">wait_all_until_error</phrase><phrase role="special">(</phrase>
<phrase role="special">[](){</phrase> <phrase role="keyword">return</phrase> <phrase role="identifier">sleeper</phrase><phrase role="special">(</phrase><phrase role="string">&quot;waue_late&quot;</phrase><phrase role="special">,</phrase> <phrase role="number">150</phrase><phrase role="special">);</phrase> <phrase role="special">},</phrase>
<phrase role="special">[](){</phrase> <phrase role="keyword">return</phrase> <phrase role="identifier">sleeper</phrase><phrase role="special">(</phrase><phrase role="string">&quot;waue_middle&quot;</phrase><phrase role="special">,</phrase> <phrase role="number">100</phrase><phrase role="special">,</phrase> <phrase role="keyword">true</phrase><phrase role="special">);</phrase> <phrase role="special">},</phrase>
<phrase role="special">[](){</phrase> <phrase role="keyword">return</phrase> <phrase role="identifier">sleeper</phrase><phrase role="special">(</phrase><phrase role="string">&quot;waue_early&quot;</phrase><phrase role="special">,</phrase> <phrase role="number">50</phrase><phrase role="special">);</phrase> <phrase role="special">});</phrase>
<phrase role="special">}</phrase> <phrase role="keyword">catch</phrase> <phrase role="special">(</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">exception</phrase> <phrase role="keyword">const</phrase><phrase role="special">&amp;</phrase> <phrase role="identifier">e</phrase><phrase role="special">)</phrase> <phrase role="special">{</phrase>
<phrase role="identifier">thrown</phrase> <phrase role="special">=</phrase> <phrase role="identifier">e</phrase><phrase role="special">.</phrase><phrase role="identifier">what</phrase><phrase role="special">();</phrase>
<phrase role="special">}</phrase>
<phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">cout</phrase> <phrase role="special">&lt;&lt;</phrase> <phrase role="string">&quot;wait_all_until_error(fail) threw '&quot;</phrase> <phrase role="special">&lt;&lt;</phrase> <phrase role="identifier">thrown</phrase>
<phrase role="special">&lt;&lt;</phrase> <phrase role="string">&quot;'&quot;</phrase> <phrase role="special">&lt;&lt;</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">endl</phrase><phrase role="special">;</phrase>
</programlisting>
</para>
<para>
<anchor id="wait_all_until_error_source"/>Naturally this complicates the
API for <code><phrase role="identifier">wait_all_until_error_source</phrase><phrase
role="special">()</phrase></code>. The caller must both retrieve a <code><phrase
role="identifier">future</phrase><phrase role="special">&lt;</phrase>
<phrase role="identifier">T</phrase> <phrase role="special">&gt;</phrase></code>
and call its <code><phrase role="identifier">get</phrase><phrase role="special">()</phrase></code>
method. It would, of course, be possible to return a façade over the consumer
end of the queue that would implicitly perform the <code><phrase role="identifier">get</phrase><phrase
role="special">()</phrase></code> and return a simple <code><phrase role="identifier">T</phrase></code>
(or throw).
</para>
<para>
The implementation is just as you would expect. Notice, however, that we
can reuse <link linkend="wait_first_outcome_impl"><code><phrase role="identifier">wait_first_outcome_impl</phrase><phrase
role="special">()</phrase></code></link>, passing the <code><phrase role="identifier">nqueue</phrase><phrase
role="special">&lt;</phrase><phrase role="identifier">T</phrase><phrase
role="special">&gt;</phrase></code> rather than <code><phrase role="identifier">queue</phrase><phrase
role="special">&lt;</phrase><phrase role="identifier">T</phrase><phrase
role="special">&gt;</phrase></code>.
</para>
<para>
<programlisting><phrase role="comment">// Return a shared_ptr&lt;buffered_channel&lt;future&lt;T&gt;&gt;&gt; from which the caller can</phrase>
<phrase role="comment">// get() each new result as it arrives, until 'closed'.</phrase>
<phrase role="keyword">template</phrase><phrase role="special">&lt;</phrase> <phrase role="keyword">typename</phrase> <phrase role="identifier">Fn</phrase><phrase role="special">,</phrase> <phrase role="keyword">typename</phrase> <phrase role="special">...</phrase> <phrase role="identifier">Fns</phrase> <phrase role="special">&gt;</phrase>
<phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">shared_ptr</phrase><phrase role="special">&lt;</phrase>
<phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">fibers</phrase><phrase role="special">::</phrase><phrase role="identifier">buffered_channel</phrase><phrase role="special">&lt;</phrase>
<phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">fibers</phrase><phrase role="special">::</phrase><phrase role="identifier">future</phrase><phrase role="special">&lt;</phrase>
<phrase role="keyword">typename</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">result_of</phrase><phrase role="special">&lt;</phrase> <phrase role="identifier">Fn</phrase><phrase role="special">()</phrase> <phrase role="special">&gt;::</phrase><phrase role="identifier">type</phrase> <phrase role="special">&gt;</phrase> <phrase role="special">&gt;</phrase> <phrase role="special">&gt;</phrase>
<phrase role="identifier">wait_all_until_error_source</phrase><phrase role="special">(</phrase> <phrase role="identifier">Fn</phrase> <phrase role="special">&amp;&amp;</phrase> <phrase role="identifier">function</phrase><phrase role="special">,</phrase> <phrase role="identifier">Fns</phrase> <phrase role="special">&amp;&amp;</phrase> <phrase role="special">...</phrase> <phrase role="identifier">functions</phrase><phrase role="special">)</phrase> <phrase role="special">{</phrase>
<phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">size_t</phrase> <phrase role="identifier">count</phrase><phrase role="special">(</phrase> <phrase role="number">1</phrase> <phrase role="special">+</phrase> <phrase role="keyword">sizeof</phrase> <phrase role="special">...</phrase> <phrase role="special">(</phrase> <phrase role="identifier">functions</phrase><phrase role="special">)</phrase> <phrase role="special">);</phrase>
<phrase role="keyword">typedef</phrase> <phrase role="keyword">typename</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">result_of</phrase><phrase role="special">&lt;</phrase> <phrase role="identifier">Fn</phrase><phrase role="special">()</phrase> <phrase role="special">&gt;::</phrase><phrase role="identifier">type</phrase> <phrase role="identifier">return_t</phrase><phrase role="special">;</phrase>
<phrase role="keyword">typedef</phrase> <phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">fibers</phrase><phrase role="special">::</phrase><phrase role="identifier">future</phrase><phrase role="special">&lt;</phrase> <phrase role="identifier">return_t</phrase> <phrase role="special">&gt;</phrase> <phrase role="identifier">future_t</phrase><phrase role="special">;</phrase>
<phrase role="keyword">typedef</phrase> <phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">fibers</phrase><phrase role="special">::</phrase><phrase role="identifier">buffered_channel</phrase><phrase role="special">&lt;</phrase> <phrase role="identifier">future_t</phrase> <phrase role="special">&gt;</phrase> <phrase role="identifier">channel_t</phrase><phrase role="special">;</phrase>
<phrase role="comment">// make the channel</phrase>
<phrase role="keyword">auto</phrase> <phrase role="identifier">chanp</phrase><phrase role="special">(</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">make_shared</phrase><phrase role="special">&lt;</phrase> <phrase role="identifier">channel_t</phrase> <phrase role="special">&gt;(</phrase> <phrase role="number">64</phrase><phrase role="special">)</phrase> <phrase role="special">);</phrase>
<phrase role="comment">// and make an nchannel facade to close it after 'count' items</phrase>
<phrase role="keyword">auto</phrase> <phrase role="identifier">ncp</phrase><phrase role="special">(</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">make_shared</phrase><phrase role="special">&lt;</phrase> <phrase role="identifier">nchannel</phrase><phrase role="special">&lt;</phrase> <phrase role="identifier">future_t</phrase> <phrase role="special">&gt;</phrase> <phrase role="special">&gt;(</phrase> <phrase role="identifier">chanp</phrase><phrase role="special">,</phrase> <phrase role="identifier">count</phrase><phrase role="special">)</phrase> <phrase role="special">);</phrase>
<phrase role="comment">// pass that nchannel facade to all the relevant fibers</phrase>
<phrase role="identifier">wait_first_outcome_impl</phrase><phrase role="special">&lt;</phrase> <phrase role="identifier">return_t</phrase> <phrase role="special">&gt;(</phrase> <phrase role="identifier">ncp</phrase><phrase role="special">,</phrase>
<phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">forward</phrase><phrase role="special">&lt;</phrase> <phrase role="identifier">Fn</phrase> <phrase role="special">&gt;(</phrase> <phrase role="identifier">function</phrase><phrase role="special">),</phrase>
<phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">forward</phrase><phrase role="special">&lt;</phrase> <phrase role="identifier">Fns</phrase> <phrase role="special">&gt;(</phrase> <phrase role="identifier">functions</phrase><phrase role="special">)</phrase> <phrase role="special">...</phrase> <phrase role="special">);</phrase>
<phrase role="comment">// then return the channel for consumer</phrase>
<phrase role="keyword">return</phrase> <phrase role="identifier">chanp</phrase><phrase role="special">;</phrase>
<phrase role="special">}</phrase>
</programlisting>
</para>
<para>
For example:
</para>
<para>
<programlisting><phrase role="keyword">typedef</phrase> <phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">fibers</phrase><phrase role="special">::</phrase><phrase role="identifier">future</phrase><phrase role="special">&lt;</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">string</phrase> <phrase role="special">&gt;</phrase> <phrase role="identifier">future_t</phrase><phrase role="special">;</phrase>
<phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">shared_ptr</phrase><phrase role="special">&lt;</phrase> <phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">fibers</phrase><phrase role="special">::</phrase><phrase role="identifier">buffered_channel</phrase><phrase role="special">&lt;</phrase> <phrase role="identifier">future_t</phrase> <phrase role="special">&gt;</phrase> <phrase role="special">&gt;</phrase> <phrase role="identifier">chan</phrase> <phrase role="special">=</phrase>
<phrase role="identifier">wait_all_until_error_source</phrase><phrase role="special">(</phrase>
<phrase role="special">[](){</phrase> <phrase role="keyword">return</phrase> <phrase role="identifier">sleeper</phrase><phrase role="special">(</phrase><phrase role="string">&quot;wauess_third&quot;</phrase><phrase role="special">,</phrase> <phrase role="number">150</phrase><phrase role="special">);</phrase> <phrase role="special">},</phrase>
<phrase role="special">[](){</phrase> <phrase role="keyword">return</phrase> <phrase role="identifier">sleeper</phrase><phrase role="special">(</phrase><phrase role="string">&quot;wauess_second&quot;</phrase><phrase role="special">,</phrase> <phrase role="number">100</phrase><phrase role="special">);</phrase> <phrase role="special">},</phrase>
<phrase role="special">[](){</phrase> <phrase role="keyword">return</phrase> <phrase role="identifier">sleeper</phrase><phrase role="special">(</phrase><phrase role="string">&quot;wauess_first&quot;</phrase><phrase role="special">,</phrase> <phrase role="number">50</phrase><phrase role="special">);</phrase> <phrase role="special">});</phrase>
<phrase role="identifier">future_t</phrase> <phrase role="identifier">future</phrase><phrase role="special">;</phrase>
<phrase role="keyword">while</phrase> <phrase role="special">(</phrase> <phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">fibers</phrase><phrase role="special">::</phrase><phrase role="identifier">channel_op_status</phrase><phrase role="special">::</phrase><phrase role="identifier">success</phrase> <phrase role="special">==</phrase> <phrase role="identifier">chan</phrase><phrase role="special">-&gt;</phrase><phrase role="identifier">pop</phrase><phrase role="special">(</phrase> <phrase role="identifier">future</phrase><phrase role="special">)</phrase> <phrase role="special">)</phrase> <phrase role="special">{</phrase>
<phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">string</phrase> <phrase role="identifier">value</phrase><phrase role="special">(</phrase> <phrase role="identifier">future</phrase><phrase role="special">.</phrase><phrase role="identifier">get</phrase><phrase role="special">()</phrase> <phrase role="special">);</phrase>
<phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">cout</phrase> <phrase role="special">&lt;&lt;</phrase> <phrase role="string">&quot;wait_all_until_error_source(success) =&gt; '&quot;</phrase> <phrase role="special">&lt;&lt;</phrase> <phrase role="identifier">value</phrase>
<phrase role="special">&lt;&lt;</phrase> <phrase role="string">&quot;'&quot;</phrase> <phrase role="special">&lt;&lt;</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">endl</phrase><phrase role="special">;</phrase>
<phrase role="special">}</phrase>
</programlisting>
</para>
</section>
<section id="fiber.when_any.when_all_functionality.wait_all__collecting_all_exceptions">
<title><link linkend="fiber.when_any.when_all_functionality.wait_all__collecting_all_exceptions">wait_all,
collecting all exceptions</link></title>
<para>
<anchor id="wait_all_collect_errors"/>Given <link linkend="wait_all_until_error_source"><code><phrase
role="identifier">wait_all_until_error_source</phrase><phrase role="special">()</phrase></code></link>,
it might be more reasonable to make a <code><phrase role="identifier">wait_all_</phrase><phrase
role="special">...()</phrase></code> that collects <emphasis>all</emphasis>
errors instead of presenting only the first:
</para>
<para>
<programlisting><phrase role="keyword">template</phrase><phrase role="special">&lt;</phrase> <phrase role="keyword">typename</phrase> <phrase role="identifier">Fn</phrase><phrase role="special">,</phrase> <phrase role="keyword">typename</phrase> <phrase role="special">...</phrase> <phrase role="identifier">Fns</phrase> <phrase role="special">&gt;</phrase>
<phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">vector</phrase><phrase role="special">&lt;</phrase> <phrase role="keyword">typename</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">result_of</phrase><phrase role="special">&lt;</phrase> <phrase role="identifier">Fn</phrase><phrase role="special">()</phrase> <phrase role="special">&gt;::</phrase><phrase role="identifier">type</phrase> <phrase role="special">&gt;</phrase>
<phrase role="identifier">wait_all_collect_errors</phrase><phrase role="special">(</phrase> <phrase role="identifier">Fn</phrase> <phrase role="special">&amp;&amp;</phrase> <phrase role="identifier">function</phrase><phrase role="special">,</phrase> <phrase role="identifier">Fns</phrase> <phrase role="special">&amp;&amp;</phrase> <phrase role="special">...</phrase> <phrase role="identifier">functions</phrase><phrase role="special">)</phrase> <phrase role="special">{</phrase>
<phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">size_t</phrase> <phrase role="identifier">count</phrase><phrase role="special">(</phrase> <phrase role="number">1</phrase> <phrase role="special">+</phrase> <phrase role="keyword">sizeof</phrase> <phrase role="special">...</phrase> <phrase role="special">(</phrase> <phrase role="identifier">functions</phrase><phrase role="special">)</phrase> <phrase role="special">);</phrase>
<phrase role="keyword">typedef</phrase> <phrase role="keyword">typename</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">result_of</phrase><phrase role="special">&lt;</phrase> <phrase role="identifier">Fn</phrase><phrase role="special">()</phrase> <phrase role="special">&gt;::</phrase><phrase role="identifier">type</phrase> <phrase role="identifier">return_t</phrase><phrase role="special">;</phrase>
<phrase role="keyword">typedef</phrase> <phrase role="keyword">typename</phrase> <phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">fibers</phrase><phrase role="special">::</phrase><phrase role="identifier">future</phrase><phrase role="special">&lt;</phrase> <phrase role="identifier">return_t</phrase> <phrase role="special">&gt;</phrase> <phrase role="identifier">future_t</phrase><phrase role="special">;</phrase>
<phrase role="keyword">typedef</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">vector</phrase><phrase role="special">&lt;</phrase> <phrase role="identifier">return_t</phrase> <phrase role="special">&gt;</phrase> <phrase role="identifier">vector_t</phrase><phrase role="special">;</phrase>
<phrase role="identifier">vector_t</phrase> <phrase role="identifier">results</phrase><phrase role="special">;</phrase>
<phrase role="identifier">results</phrase><phrase role="special">.</phrase><phrase role="identifier">reserve</phrase><phrase role="special">(</phrase> <phrase role="identifier">count</phrase><phrase role="special">);</phrase>
<phrase role="identifier">exception_list</phrase> <phrase role="identifier">exceptions</phrase><phrase role="special">(</phrase><phrase role="string">&quot;wait_all_collect_errors() exceptions&quot;</phrase><phrase role="special">);</phrase>
<phrase role="comment">// get channel</phrase>
<phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">shared_ptr</phrase><phrase role="special">&lt;</phrase>
<phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">fibers</phrase><phrase role="special">::</phrase><phrase role="identifier">buffered_channel</phrase><phrase role="special">&lt;</phrase> <phrase role="identifier">future_t</phrase> <phrase role="special">&gt;</phrase> <phrase role="special">&gt;</phrase> <phrase role="identifier">chan</phrase><phrase role="special">(</phrase>
<phrase role="identifier">wait_all_until_error_source</phrase><phrase role="special">(</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">forward</phrase><phrase role="special">&lt;</phrase> <phrase role="identifier">Fn</phrase> <phrase role="special">&gt;(</phrase> <phrase role="identifier">function</phrase><phrase role="special">),</phrase>
<phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">forward</phrase><phrase role="special">&lt;</phrase> <phrase role="identifier">Fns</phrase> <phrase role="special">&gt;(</phrase> <phrase role="identifier">functions</phrase><phrase role="special">)</phrase> <phrase role="special">...</phrase> <phrase role="special">)</phrase> <phrase role="special">);</phrase>
<phrase role="comment">// fill results and/or exceptions vectors</phrase>
<phrase role="identifier">future_t</phrase> <phrase role="identifier">future</phrase><phrase role="special">;</phrase>
<phrase role="keyword">while</phrase> <phrase role="special">(</phrase> <phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">fibers</phrase><phrase role="special">::</phrase><phrase role="identifier">channel_op_status</phrase><phrase role="special">::</phrase><phrase role="identifier">success</phrase> <phrase role="special">==</phrase> <phrase role="identifier">chan</phrase><phrase role="special">-&gt;</phrase><phrase role="identifier">pop</phrase><phrase role="special">(</phrase> <phrase role="identifier">future</phrase><phrase role="special">)</phrase> <phrase role="special">)</phrase> <phrase role="special">{</phrase>
<phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">exception_ptr</phrase> <phrase role="identifier">exp</phrase> <phrase role="special">=</phrase> <phrase role="identifier">future</phrase><phrase role="special">.</phrase><phrase role="identifier">get_exception_ptr</phrase><phrase role="special">();</phrase>
<phrase role="keyword">if</phrase> <phrase role="special">(</phrase> <phrase role="special">!</phrase> <phrase role="identifier">exp</phrase><phrase role="special">)</phrase> <phrase role="special">{</phrase>
<phrase role="identifier">results</phrase><phrase role="special">.</phrase><phrase role="identifier">push_back</phrase><phrase role="special">(</phrase> <phrase role="identifier">future</phrase><phrase role="special">.</phrase><phrase role="identifier">get</phrase><phrase role="special">()</phrase> <phrase role="special">);</phrase>
<phrase role="special">}</phrase> <phrase role="keyword">else</phrase> <phrase role="special">{</phrase>
<phrase role="identifier">exceptions</phrase><phrase role="special">.</phrase><phrase role="identifier">add</phrase><phrase role="special">(</phrase> <phrase role="identifier">exp</phrase><phrase role="special">);</phrase>
<phrase role="special">}</phrase>
<phrase role="special">}</phrase>
<phrase role="comment">// if there were any exceptions, throw</phrase>
<phrase role="keyword">if</phrase> <phrase role="special">(</phrase> <phrase role="identifier">exceptions</phrase><phrase role="special">.</phrase><phrase role="identifier">size</phrase><phrase role="special">()</phrase> <phrase role="special">)</phrase> <phrase role="special">{</phrase>
<phrase role="keyword">throw</phrase> <phrase role="identifier">exceptions</phrase><phrase role="special">;</phrase>
<phrase role="special">}</phrase>
<phrase role="comment">// no exceptions: return vector to caller</phrase>
<phrase role="keyword">return</phrase> <phrase role="identifier">results</phrase><phrase role="special">;</phrase>
<phrase role="special">}</phrase>
</programlisting>
</para>
<para>
The implementation is a simple variation on <link linkend="wait_first_success"><code><phrase
role="identifier">wait_first_success</phrase><phrase role="special">()</phrase></code></link>,
using the same <link linkend="exception_list"><code><phrase role="identifier">exception_list</phrase></code></link>
exception class.
</para>
</section>
<section id="fiber.when_any.when_all_functionality.when_all__heterogeneous_types">
<title><link linkend="fiber.when_any.when_all_functionality.when_all__heterogeneous_types">when_all,
heterogeneous types</link></title>
<para>
But what about the case when we must wait for all results of different
types?
</para>
<para>
We can present an API that is frankly quite cool. Consider a sample struct:
</para>
<para>
<programlisting><phrase role="keyword">struct</phrase> <phrase role="identifier">Data</phrase> <phrase role="special">{</phrase>
<phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">string</phrase> <phrase role="identifier">str</phrase><phrase role="special">;</phrase>
<phrase role="keyword">double</phrase> <phrase role="identifier">inexact</phrase><phrase role="special">;</phrase>
<phrase role="keyword">int</phrase> <phrase role="identifier">exact</phrase><phrase role="special">;</phrase>
<phrase role="keyword">friend</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">ostream</phrase><phrase role="special">&amp;</phrase> <phrase role="keyword">operator</phrase><phrase role="special">&lt;&lt;(</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">ostream</phrase><phrase role="special">&amp;</phrase> <phrase role="identifier">out</phrase><phrase role="special">,</phrase> <phrase role="identifier">Data</phrase> <phrase role="keyword">const</phrase><phrase role="special">&amp;</phrase> <phrase role="identifier">data</phrase><phrase role="special">);</phrase>
<phrase role="special">...</phrase>
<phrase role="special">};</phrase>
</programlisting>
</para>
<para>
Let's fill its members from task functions all running concurrently:
</para>
<para>
<programlisting><phrase role="identifier">Data</phrase> <phrase role="identifier">data</phrase> <phrase role="special">=</phrase> <phrase role="identifier">wait_all_members</phrase><phrase role="special">&lt;</phrase> <phrase role="identifier">Data</phrase> <phrase role="special">&gt;(</phrase>
<phrase role="special">[](){</phrase> <phrase role="keyword">return</phrase> <phrase role="identifier">sleeper</phrase><phrase role="special">(</phrase><phrase role="string">&quot;wams_left&quot;</phrase><phrase role="special">,</phrase> <phrase role="number">100</phrase><phrase role="special">);</phrase> <phrase role="special">},</phrase>
<phrase role="special">[](){</phrase> <phrase role="keyword">return</phrase> <phrase role="identifier">sleeper</phrase><phrase role="special">(</phrase><phrase role="number">3.14</phrase><phrase role="special">,</phrase> <phrase role="number">150</phrase><phrase role="special">);</phrase> <phrase role="special">},</phrase>
<phrase role="special">[](){</phrase> <phrase role="keyword">return</phrase> <phrase role="identifier">sleeper</phrase><phrase role="special">(</phrase><phrase role="number">17</phrase><phrase role="special">,</phrase> <phrase role="number">50</phrase><phrase role="special">);</phrase> <phrase role="special">});</phrase>
<phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">cout</phrase> <phrase role="special">&lt;&lt;</phrase> <phrase role="string">&quot;wait_all_members&lt;Data&gt;(success) =&gt; &quot;</phrase> <phrase role="special">&lt;&lt;</phrase> <phrase role="identifier">data</phrase> <phrase role="special">&lt;&lt;</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">endl</phrase><phrase role="special">;</phrase>
</programlisting>
</para>
<para>
Note that for this case, we abandon the notion of capturing the earliest
result first, and so on: we must fill exactly the passed struct in left-to-right
order.
</para>
<para>
That permits a beautifully simple implementation:
</para>
<para>
<programlisting><phrase role="comment">// Explicitly pass Result. This can be any type capable of being initialized</phrase>
<phrase role="comment">// from the results of the passed functions, such as a struct.</phrase>
<phrase role="keyword">template</phrase><phrase role="special">&lt;</phrase> <phrase role="keyword">typename</phrase> <phrase role="identifier">Result</phrase><phrase role="special">,</phrase> <phrase role="keyword">typename</phrase> <phrase role="special">...</phrase> <phrase role="identifier">Fns</phrase> <phrase role="special">&gt;</phrase>
<phrase role="identifier">Result</phrase> <phrase role="identifier">wait_all_members</phrase><phrase role="special">(</phrase> <phrase role="identifier">Fns</phrase> <phrase role="special">&amp;&amp;</phrase> <phrase role="special">...</phrase> <phrase role="identifier">functions</phrase><phrase role="special">)</phrase> <phrase role="special">{</phrase>
<phrase role="comment">// Run each of the passed functions on a separate fiber, passing all their</phrase>
<phrase role="comment">// futures to helper function for processing.</phrase>
<phrase role="keyword">return</phrase> <phrase role="identifier">wait_all_members_get</phrase><phrase role="special">&lt;</phrase> <phrase role="identifier">Result</phrase> <phrase role="special">&gt;(</phrase>
<phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">fibers</phrase><phrase role="special">::</phrase><phrase role="identifier">async</phrase><phrase role="special">(</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">forward</phrase><phrase role="special">&lt;</phrase> <phrase role="identifier">Fns</phrase> <phrase role="special">&gt;(</phrase> <phrase role="identifier">functions</phrase><phrase role="special">)</phrase> <phrase role="special">)</phrase> <phrase role="special">...</phrase> <phrase role="special">);</phrase>
<phrase role="special">}</phrase>
</programlisting>
</para>
<para>
<programlisting><phrase role="keyword">template</phrase><phrase role="special">&lt;</phrase> <phrase role="keyword">typename</phrase> <phrase role="identifier">Result</phrase><phrase role="special">,</phrase> <phrase role="keyword">typename</phrase> <phrase role="special">...</phrase> <phrase role="identifier">Futures</phrase> <phrase role="special">&gt;</phrase>
<phrase role="identifier">Result</phrase> <phrase role="identifier">wait_all_members_get</phrase><phrase role="special">(</phrase> <phrase role="identifier">Futures</phrase> <phrase role="special">&amp;&amp;</phrase> <phrase role="special">...</phrase> <phrase role="identifier">futures</phrase><phrase role="special">)</phrase> <phrase role="special">{</phrase>
<phrase role="comment">// Fetch the results from the passed futures into Result's initializer</phrase>
<phrase role="comment">// list. It's true that the get() calls here will block the implicit</phrase>
<phrase role="comment">// iteration over futures -- but that doesn't matter because we won't be</phrase>
<phrase role="comment">// done until the slowest of them finishes anyway. As results are</phrase>
<phrase role="comment">// processed in argument-list order rather than order of completion, the</phrase>
<phrase role="comment">// leftmost get() to throw an exception will cause that exception to</phrase>
<phrase role="comment">// propagate to the caller.</phrase>
<phrase role="keyword">return</phrase> <phrase role="identifier">Result</phrase><phrase role="special">{</phrase> <phrase role="identifier">futures</phrase><phrase role="special">.</phrase><phrase role="identifier">get</phrase><phrase role="special">()</phrase> <phrase role="special">...</phrase> <phrase role="special">};</phrase>
<phrase role="special">}</phrase>
</programlisting>
</para>
<para>
It is tempting to try to implement <code><phrase role="identifier">wait_all_members</phrase><phrase
role="special">()</phrase></code> as a one-liner like this:
</para>
<programlisting><phrase role="keyword">return</phrase> <phrase role="identifier">Result</phrase><phrase role="special">{</phrase> <phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">fibers</phrase><phrase role="special">::</phrase><phrase role="identifier">async</phrase><phrase role="special">(</phrase><phrase role="identifier">functions</phrase><phrase role="special">).</phrase><phrase role="identifier">get</phrase><phrase role="special">()...</phrase> <phrase role="special">};</phrase>
</programlisting>
<para>
The trouble with this tactic is that it would serialize all the task functions.
The runtime makes a single pass through <code><phrase role="identifier">functions</phrase></code>,
calling <link linkend="fibers_async"><code>fibers::async()</code></link> for each and then immediately calling
<link linkend="future_get"><code>future::get()</code></link> on its returned <code><phrase role="identifier">future</phrase><phrase
role="special">&lt;&gt;</phrase></code>. That blocks the implicit loop.
The above is almost equivalent to writing:
</para>
<programlisting><phrase role="keyword">return</phrase> <phrase role="identifier">Result</phrase><phrase role="special">{</phrase> <phrase role="identifier">functions</phrase><phrase role="special">()...</phrase> <phrase role="special">};</phrase>
</programlisting>
<para>
in which, of course, there is no concurrency at all.
</para>
<para>
Passing the argument pack through a function-call boundary (<code><phrase
role="identifier">wait_all_members_get</phrase><phrase role="special">()</phrase></code>)
forces the runtime to make <emphasis>two</emphasis> passes: one in <code><phrase
role="identifier">wait_all_members</phrase><phrase role="special">()</phrase></code>
to collect the <code><phrase role="identifier">future</phrase><phrase role="special">&lt;&gt;</phrase></code>s
from all the <code><phrase role="identifier">async</phrase><phrase role="special">()</phrase></code>
calls, the second in <code><phrase role="identifier">wait_all_members_get</phrase><phrase
role="special">()</phrase></code> to fetch each of the results.
</para>
<para>
As noted in comments, within the <code><phrase role="identifier">wait_all_members_get</phrase><phrase
role="special">()</phrase></code> parameter pack expansion pass, the blocking
behavior of <code><phrase role="identifier">get</phrase><phrase role="special">()</phrase></code>
becomes irrelevant. Along the way, we will hit the <code><phrase role="identifier">get</phrase><phrase
role="special">()</phrase></code> for the slowest task function; after
that every subsequent <code><phrase role="identifier">get</phrase><phrase
role="special">()</phrase></code> will complete in trivial time.
</para>
<para>
By the way, we could also use this same API to fill a vector or other collection:
</para>
<para>
<programlisting><phrase role="comment">// If we don't care about obtaining results as soon as they arrive, and we</phrase>
<phrase role="comment">// prefer a result vector in passed argument order rather than completion</phrase>
<phrase role="comment">// order, wait_all_members() is another possible implementation of</phrase>
<phrase role="comment">// wait_all_until_error().</phrase>
<phrase role="keyword">auto</phrase> <phrase role="identifier">strings</phrase> <phrase role="special">=</phrase> <phrase role="identifier">wait_all_members</phrase><phrase role="special">&lt;</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">vector</phrase><phrase role="special">&lt;</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">string</phrase> <phrase role="special">&gt;</phrase> <phrase role="special">&gt;(</phrase>
<phrase role="special">[](){</phrase> <phrase role="keyword">return</phrase> <phrase role="identifier">sleeper</phrase><phrase role="special">(</phrase><phrase role="string">&quot;wamv_left&quot;</phrase><phrase role="special">,</phrase> <phrase role="number">150</phrase><phrase role="special">);</phrase> <phrase role="special">},</phrase>
<phrase role="special">[](){</phrase> <phrase role="keyword">return</phrase> <phrase role="identifier">sleeper</phrase><phrase role="special">(</phrase><phrase role="string">&quot;wamv_middle&quot;</phrase><phrase role="special">,</phrase> <phrase role="number">100</phrase><phrase role="special">);</phrase> <phrase role="special">},</phrase>
<phrase role="special">[](){</phrase> <phrase role="keyword">return</phrase> <phrase role="identifier">sleeper</phrase><phrase role="special">(</phrase><phrase role="string">&quot;wamv_right&quot;</phrase><phrase role="special">,</phrase> <phrase role="number">50</phrase><phrase role="special">);</phrase> <phrase role="special">});</phrase>
<phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">cout</phrase> <phrase role="special">&lt;&lt;</phrase> <phrase role="string">&quot;wait_all_members&lt;vector&gt;() =&gt;&quot;</phrase><phrase role="special">;</phrase>
<phrase role="keyword">for</phrase> <phrase role="special">(</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">string</phrase> <phrase role="keyword">const</phrase><phrase role="special">&amp;</phrase> <phrase role="identifier">str</phrase> <phrase role="special">:</phrase> <phrase role="identifier">strings</phrase><phrase role="special">)</phrase> <phrase role="special">{</phrase>
<phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">cout</phrase> <phrase role="special">&lt;&lt;</phrase> <phrase role="string">&quot; '&quot;</phrase> <phrase role="special">&lt;&lt;</phrase> <phrase role="identifier">str</phrase> <phrase role="special">&lt;&lt;</phrase> <phrase role="string">&quot;'&quot;</phrase><phrase role="special">;</phrase>
<phrase role="special">}</phrase>
<phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">cout</phrase> <phrase role="special">&lt;&lt;</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">endl</phrase><phrase role="special">;</phrase>
</programlisting>
</para>
</section>
</section>
</section>
<section id="fiber.integration">
<title><anchor id="integration"/><link linkend="fiber.integration">Sharing a
Thread with Another Main Loop</link></title>
<section id="fiber.integration.overview">
<title><link linkend="fiber.integration.overview">Overview</link></title>
<para>
As always with cooperative concurrency, it is important not to let any one
fiber monopolize the processor too long: that could <quote>starve</quote>
other ready fibers. This section discusses a couple of solutions.
</para>
</section>
<section id="fiber.integration.event_driven_program">
<title><link linkend="fiber.integration.event_driven_program">Event-Driven
Program</link></title>
<para>
Consider a classic event-driven program, organized around a main loop that
fetches and dispatches incoming I/O events. You are introducing <emphasis
role="bold">Boost.Fiber</emphasis> because certain asynchronous I/O sequences
are logically sequential, and for those you want to write and maintain code
that looks and acts sequential.
</para>
<para>
You are launching fibers on the application&#8217;s main thread because certain
of their actions will affect its user interface, and the application&#8217;s UI
framework permits UI operations only on the main thread. Or perhaps those
fibers need access to main-thread data, and it would be too expensive in
runtime (or development time) to robustly defend every such data item with
thread synchronization primitives.
</para>
<para>
You must ensure that the application&#8217;s main loop <emphasis>itself</emphasis>
doesn&#8217;t monopolize the processor: that the fibers it launches will get the
CPU cycles they need.
</para>
<para>
The solution is the same as for any fiber that might claim the CPU for an
extended time: introduce calls to <link linkend="this_fiber_yield"><code>this_fiber::yield()</code></link>. The
most straightforward approach is to call <code><phrase role="identifier">yield</phrase><phrase
role="special">()</phrase></code> on every iteration of your existing main
loop. In effect, this unifies the application&#8217;s main loop with <emphasis role="bold">Boost.Fiber</emphasis>&#8217;s
internal main loop. <code><phrase role="identifier">yield</phrase><phrase
role="special">()</phrase></code> allows the fiber manager to run any fibers
that have become ready since the previous iteration of the application&#8217;s main
loop. When these fibers have had a turn, control passes to the thread&#8217;s main
fiber, which returns from <code><phrase role="identifier">yield</phrase><phrase
role="special">()</phrase></code> and resumes the application&#8217;s main loop.
</para>
</section>
<section id="fiber.integration.embedded_main_loop">
<title><anchor id="embedded_main_loop"/><link linkend="fiber.integration.embedded_main_loop">Embedded
Main Loop</link></title>
<para>
More challenging is when the application&#8217;s main loop is embedded in some other
library or framework. Such an application will typically, after performing
all necessary setup, pass control to some form of <code><phrase role="identifier">run</phrase><phrase
role="special">()</phrase></code> function from which control does not return
until application shutdown.
</para>
<para>
A <ulink url="http://www.boost.org/doc/libs/release/libs/asio/index.html">Boost.Asio</ulink>
program might call <ulink url="http://www.boost.org/doc/libs/release/doc/html/boost_asio/reference/io_service/run.html"><code><phrase
role="identifier">io_service</phrase><phrase role="special">::</phrase><phrase
role="identifier">run</phrase><phrase role="special">()</phrase></code></ulink>
in this way.
</para>
<para>
In general, the trick is to arrange to pass control to <link linkend="this_fiber_yield"><code>this_fiber::yield()</code></link> frequently.
You could use an <ulink url="http://www.boost.org/doc/libs/release/doc/html/boost_asio/reference/high_resolution_timer.html">Asio
timer</ulink> for that purpose. You could instantiate the timer, arranging
to call a handler function when the timer expires. The handler function could
call <code><phrase role="identifier">yield</phrase><phrase role="special">()</phrase></code>,
then reset the timer and arrange to wake up again on its next expiration.
</para>
<para>
Since, in this thought experiment, we always pass control to the fiber manager
via <code><phrase role="identifier">yield</phrase><phrase role="special">()</phrase></code>,
the calling fiber is never blocked. Therefore there is always at least one
ready fiber. Therefore the fiber manager never calls <link linkend="algorithm_suspend_until"><code>algorithm::suspend_until()</code></link>.
</para>
<para>
Using <ulink url="http://www.boost.org/doc/libs/release/doc/html/boost_asio/reference/io_service/post.html"><code><phrase
role="identifier">io_service</phrase><phrase role="special">::</phrase><phrase
role="identifier">post</phrase><phrase role="special">()</phrase></code></ulink>
instead of setting a timer for some nonzero interval would be unfriendly
to other threads. When all I/O is pending and all fibers are blocked, the
io_service and the fiber manager would simply spin the CPU, passing control
back and forth to each other. Using a timer allows tuning the responsiveness
of this thread relative to others.
</para>
</section>
<section id="fiber.integration.deeper_dive_into___boost_asio__">
<title><link linkend="fiber.integration.deeper_dive_into___boost_asio__">Deeper
Dive into <ulink url="http://www.boost.org/doc/libs/release/libs/asio/index.html">Boost.Asio</ulink></link></title>
<para>
By now the alert reader is thinking: but surely, with Asio in particular,
we ought to be able to do much better than periodic polling pings!
</para>
<para>
This turns out to be surprisingly tricky. We present a possible approach
in <ulink url="../../examples/asio/round_robin.hpp"><code><phrase role="identifier">examples</phrase><phrase
role="special">/</phrase><phrase role="identifier">asio</phrase><phrase role="special">/</phrase><phrase
role="identifier">round_robin</phrase><phrase role="special">.</phrase><phrase
role="identifier">hpp</phrase></code></ulink>.
</para>
<para>
One consequence of using <ulink url="http://www.boost.org/doc/libs/release/libs/asio/index.html">Boost.Asio</ulink>
is that you must always let Asio suspend the running thread. Since Asio is
aware of pending I/O requests, it can arrange to suspend the thread in such
a way that the OS will wake it on I/O completion. No one else has sufficient
knowledge.
</para>
<para>
So the fiber scheduler must depend on Asio for suspension and resumption.
It requires Asio handler calls to wake it.
</para>
<para>
One dismaying implication is that we cannot support multiple threads calling
<ulink url="http://www.boost.org/doc/libs/release/doc/html/boost_asio/reference/io_service/run.html"><code><phrase
role="identifier">io_service</phrase><phrase role="special">::</phrase><phrase
role="identifier">run</phrase><phrase role="special">()</phrase></code></ulink>
on the same <code><phrase role="identifier">io_service</phrase></code> instance.
The reason is that Asio provides no way to constrain a particular handler
to be called only on a specified thread. A fiber scheduler instance is locked
to a particular thread: that instance cannot manage any other thread&#8217;s fibers.
Yet if we allow multiple threads to call <code><phrase role="identifier">io_service</phrase><phrase
role="special">::</phrase><phrase role="identifier">run</phrase><phrase role="special">()</phrase></code>
on the same <code><phrase role="identifier">io_service</phrase></code> instance,
a fiber scheduler which needs to sleep can have no guarantee that it will
reawaken in a timely manner. It can set an Asio timer, as described above
&mdash; but that timer&#8217;s handler may well execute on a different thread!
</para>
<para>
Another implication is that since an Asio-aware fiber scheduler (not to mention
<link linkend="callbacks_asio"><code><phrase role="identifier">boost</phrase><phrase
role="special">::</phrase><phrase role="identifier">fibers</phrase><phrase
role="special">::</phrase><phrase role="identifier">asio</phrase><phrase
role="special">::</phrase><phrase role="identifier">yield</phrase></code></link>)
depends on handler calls from the <code><phrase role="identifier">io_service</phrase></code>,
it is the application&#8217;s responsibility to ensure that <ulink url="http://www.boost.org/doc/libs/release/doc/html/boost_asio/reference/io_service/stop.html"><code><phrase
role="identifier">io_service</phrase><phrase role="special">::</phrase><phrase
role="identifier">stop</phrase><phrase role="special">()</phrase></code></ulink>
is not called until every fiber has terminated.
</para>
<para>
It is easier to reason about the behavior of the presented <code><phrase
role="identifier">asio</phrase><phrase role="special">::</phrase><phrase
role="identifier">round_robin</phrase></code> scheduler if we require that
after initial setup, the thread&#8217;s main fiber is the fiber that calls <code><phrase
role="identifier">io_service</phrase><phrase role="special">::</phrase><phrase
role="identifier">run</phrase><phrase role="special">()</phrase></code>,
so let&#8217;s impose that requirement.
</para>
<para>
Naturally, the first thing we must do on each thread using a custom fiber
scheduler is call <link linkend="use_scheduling_algorithm"><code>use_scheduling_algorithm()</code></link>. However,
since <code><phrase role="identifier">asio</phrase><phrase role="special">::</phrase><phrase
role="identifier">round_robin</phrase></code> requires an <code><phrase role="identifier">io_service</phrase></code>
instance, we must first declare that.
</para>
<para>
<programlisting><phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">shared_ptr</phrase><phrase role="special">&lt;</phrase> <phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">asio</phrase><phrase role="special">::</phrase><phrase role="identifier">io_service</phrase> <phrase role="special">&gt;</phrase> <phrase role="identifier">io_svc</phrase> <phrase role="special">=</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">make_shared</phrase><phrase role="special">&lt;</phrase> <phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">asio</phrase><phrase role="special">::</phrase><phrase role="identifier">io_service</phrase> <phrase role="special">&gt;();</phrase>
<phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">fibers</phrase><phrase role="special">::</phrase><phrase role="identifier">use_scheduling_algorithm</phrase><phrase role="special">&lt;</phrase> <phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">fibers</phrase><phrase role="special">::</phrase><phrase role="identifier">asio</phrase><phrase role="special">::</phrase><phrase role="identifier">round_robin</phrase> <phrase role="special">&gt;(</phrase> <phrase role="identifier">io_svc</phrase><phrase role="special">);</phrase>
</programlisting>
</para>
<para>
<code><phrase role="identifier">use_scheduling_algorithm</phrase><phrase
role="special">()</phrase></code> instantiates <code><phrase role="identifier">asio</phrase><phrase
role="special">::</phrase><phrase role="identifier">round_robin</phrase></code>,
which naturally calls its constructor:
</para>
<para>
<programlisting><phrase role="identifier">round_robin</phrase><phrase role="special">(</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">shared_ptr</phrase><phrase role="special">&lt;</phrase> <phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">asio</phrase><phrase role="special">::</phrase><phrase role="identifier">io_service</phrase> <phrase role="special">&gt;</phrase> <phrase role="keyword">const</phrase><phrase role="special">&amp;</phrase> <phrase role="identifier">io_svc</phrase><phrase role="special">)</phrase> <phrase role="special">:</phrase>
<phrase role="identifier">io_svc_</phrase><phrase role="special">(</phrase> <phrase role="identifier">io_svc</phrase><phrase role="special">),</phrase>
<phrase role="identifier">suspend_timer_</phrase><phrase role="special">(</phrase> <phrase role="special">*</phrase> <phrase role="identifier">io_svc_</phrase><phrase role="special">)</phrase> <phrase role="special">{</phrase>
<phrase role="comment">// We use add_service() very deliberately. This will throw</phrase>
<phrase role="comment">// service_already_exists if you pass the same io_service instance to</phrase>
<phrase role="comment">// more than one round_robin instance.</phrase>
<phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">asio</phrase><phrase role="special">::</phrase><phrase role="identifier">add_service</phrase><phrase role="special">(</phrase> <phrase role="special">*</phrase> <phrase role="identifier">io_svc_</phrase><phrase role="special">,</phrase> <phrase role="keyword">new</phrase> <phrase role="identifier">service</phrase><phrase role="special">(</phrase> <phrase role="special">*</phrase> <phrase role="identifier">io_svc_</phrase><phrase role="special">)</phrase> <phrase role="special">);</phrase>
<phrase role="identifier">io_svc_</phrase><phrase role="special">-&gt;</phrase><phrase role="identifier">post</phrase><phrase role="special">([</phrase><phrase role="keyword">this</phrase><phrase role="special">]()</phrase> <phrase role="keyword">mutable</phrase> <phrase role="special">{</phrase>
</programlisting>
</para>
<para>
<code><phrase role="identifier">asio</phrase><phrase role="special">::</phrase><phrase
role="identifier">round_robin</phrase></code> binds the passed <code><phrase
role="identifier">io_service</phrase></code> pointer and initializes a <ulink
url="http://www.boost.org/doc/libs/release/doc/html/boost_asio/reference/steady_timer.html"><code><phrase
role="identifier">boost</phrase><phrase role="special">::</phrase><phrase
role="identifier">asio</phrase><phrase role="special">::</phrase><phrase
role="identifier">steady_timer</phrase></code></ulink>:
</para>
<para>
<programlisting><phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">shared_ptr</phrase><phrase role="special">&lt;</phrase> <phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">asio</phrase><phrase role="special">::</phrase><phrase role="identifier">io_service</phrase> <phrase role="special">&gt;</phrase> <phrase role="identifier">io_svc_</phrase><phrase role="special">;</phrase>
<phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">asio</phrase><phrase role="special">::</phrase><phrase role="identifier">steady_timer</phrase> <phrase role="identifier">suspend_timer_</phrase><phrase role="special">;</phrase>
</programlisting>
</para>
<para>
Then it calls <ulink url="http://www.boost.org/doc/libs/release/doc/html/boost_asio/reference/add_service.html"><code><phrase
role="identifier">boost</phrase><phrase role="special">::</phrase><phrase
role="identifier">asio</phrase><phrase role="special">::</phrase><phrase
role="identifier">add_service</phrase><phrase role="special">()</phrase></code></ulink>
with a nested <code><phrase role="identifier">service</phrase></code> struct:
</para>
<para>
<programlisting><phrase role="keyword">struct</phrase> <phrase role="identifier">service</phrase> <phrase role="special">:</phrase> <phrase role="keyword">public</phrase> <phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">asio</phrase><phrase role="special">::</phrase><phrase role="identifier">io_service</phrase><phrase role="special">::</phrase><phrase role="identifier">service</phrase> <phrase role="special">{</phrase>
<phrase role="keyword">static</phrase> <phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">asio</phrase><phrase role="special">::</phrase><phrase role="identifier">io_service</phrase><phrase role="special">::</phrase><phrase role="identifier">id</phrase> <phrase role="identifier">id</phrase><phrase role="special">;</phrase>
<phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">unique_ptr</phrase><phrase role="special">&lt;</phrase> <phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">asio</phrase><phrase role="special">::</phrase><phrase role="identifier">io_service</phrase><phrase role="special">::</phrase><phrase role="identifier">work</phrase> <phrase role="special">&gt;</phrase> <phrase role="identifier">work_</phrase><phrase role="special">;</phrase>
<phrase role="identifier">service</phrase><phrase role="special">(</phrase> <phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">asio</phrase><phrase role="special">::</phrase><phrase role="identifier">io_service</phrase> <phrase role="special">&amp;</phrase> <phrase role="identifier">io_svc</phrase><phrase role="special">)</phrase> <phrase role="special">:</phrase>
<phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">asio</phrase><phrase role="special">::</phrase><phrase role="identifier">io_service</phrase><phrase role="special">::</phrase><phrase role="identifier">service</phrase><phrase role="special">(</phrase> <phrase role="identifier">io_svc</phrase><phrase role="special">),</phrase>
<phrase role="identifier">work_</phrase><phrase role="special">{</phrase> <phrase role="keyword">new</phrase> <phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">asio</phrase><phrase role="special">::</phrase><phrase role="identifier">io_service</phrase><phrase role="special">::</phrase><phrase role="identifier">work</phrase><phrase role="special">(</phrase> <phrase role="identifier">io_svc</phrase><phrase role="special">)</phrase> <phrase role="special">}</phrase> <phrase role="special">{</phrase>
<phrase role="special">}</phrase>
<phrase role="keyword">virtual</phrase> <phrase role="special">~</phrase><phrase role="identifier">service</phrase><phrase role="special">()</phrase> <phrase role="special">{}</phrase>
<phrase role="identifier">service</phrase><phrase role="special">(</phrase> <phrase role="identifier">service</phrase> <phrase role="keyword">const</phrase><phrase role="special">&amp;)</phrase> <phrase role="special">=</phrase> <phrase role="keyword">delete</phrase><phrase role="special">;</phrase>
<phrase role="identifier">service</phrase> <phrase role="special">&amp;</phrase> <phrase role="keyword">operator</phrase><phrase role="special">=(</phrase> <phrase role="identifier">service</phrase> <phrase role="keyword">const</phrase><phrase role="special">&amp;)</phrase> <phrase role="special">=</phrase> <phrase role="keyword">delete</phrase><phrase role="special">;</phrase>
<phrase role="keyword">void</phrase> <phrase role="identifier">shutdown_service</phrase><phrase role="special">()</phrase> <phrase role="identifier">override</phrase> <phrase role="identifier">final</phrase> <phrase role="special">{</phrase>
<phrase role="identifier">work_</phrase><phrase role="special">.</phrase><phrase role="identifier">reset</phrase><phrase role="special">();</phrase>
<phrase role="special">}</phrase>
<phrase role="special">};</phrase>
</programlisting>
</para>
<para>
... [asio_rr_service_bottom]
</para>
<para>
The <code><phrase role="identifier">service</phrase></code> struct has a
couple of roles.
</para>
<para>
Its foremost role is to manage a <literal>std::unique_ptr&lt;<ulink url="http://www.boost.org/doc/libs/release/doc/html/boost_asio/reference/io_service__work.html"><code><phrase
role="identifier">boost</phrase><phrase role="special">::</phrase><phrase
role="identifier">asio</phrase><phrase role="special">::</phrase><phrase
role="identifier">io_service</phrase><phrase role="special">::</phrase><phrase
role="identifier">work</phrase></code></ulink>&gt;</literal>. We want the
<code><phrase role="identifier">io_service</phrase></code> instance to continue
its main loop even when there is no pending Asio I/O.
</para>
<para>
But when <ulink url="http://www.boost.org/doc/libs/release/doc/html/boost_asio/reference/io_service__service/shutdown_service.html"><code><phrase
role="identifier">boost</phrase><phrase role="special">::</phrase><phrase
role="identifier">asio</phrase><phrase role="special">::</phrase><phrase
role="identifier">io_service</phrase><phrase role="special">::</phrase><phrase
role="identifier">service</phrase><phrase role="special">::</phrase><phrase
role="identifier">shutdown_service</phrase><phrase role="special">()</phrase></code></ulink>
is called, we discard the <code><phrase role="identifier">io_service</phrase><phrase
role="special">::</phrase><phrase role="identifier">work</phrase></code>
instance so the <code><phrase role="identifier">io_service</phrase></code>
can shut down properly.
</para>
<para>
Its other purpose is to <ulink url="http://www.boost.org/doc/libs/release/doc/html/boost_asio/reference/io_service/post.html"><code><phrase
role="identifier">post</phrase><phrase role="special">()</phrase></code></ulink>
a lambda (not yet shown). Let&#8217;s walk further through the example program before
coming back to explain that lambda.
</para>
<para>
The <code><phrase role="identifier">service</phrase></code> constructor returns
to <code><phrase role="identifier">asio</phrase><phrase role="special">::</phrase><phrase
role="identifier">round_robin</phrase></code>&#8217;s constructor, which returns
to <code><phrase role="identifier">use_scheduling_algorithm</phrase><phrase
role="special">()</phrase></code>, which returns to the application code.
</para>
<para>
Once it has called <code><phrase role="identifier">use_scheduling_algorithm</phrase><phrase
role="special">()</phrase></code>, the application may now launch some number
of fibers:
</para>
<para>
<programlisting><phrase role="comment">// server</phrase>
<phrase role="identifier">tcp</phrase><phrase role="special">::</phrase><phrase role="identifier">acceptor</phrase> <phrase role="identifier">a</phrase><phrase role="special">(</phrase> <phrase role="special">*</phrase> <phrase role="identifier">io_svc</phrase><phrase role="special">,</phrase> <phrase role="identifier">tcp</phrase><phrase role="special">::</phrase><phrase role="identifier">endpoint</phrase><phrase role="special">(</phrase> <phrase role="identifier">tcp</phrase><phrase role="special">::</phrase><phrase role="identifier">v4</phrase><phrase role="special">(),</phrase> <phrase role="number">9999</phrase><phrase role="special">)</phrase> <phrase role="special">);</phrase>
<phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">fibers</phrase><phrase role="special">::</phrase><phrase role="identifier">fiber</phrase><phrase role="special">(</phrase> <phrase role="identifier">server</phrase><phrase role="special">,</phrase> <phrase role="identifier">io_svc</phrase><phrase role="special">,</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">ref</phrase><phrase role="special">(</phrase> <phrase role="identifier">a</phrase><phrase role="special">)</phrase> <phrase role="special">).</phrase><phrase role="identifier">detach</phrase><phrase role="special">();</phrase>
<phrase role="comment">// client</phrase>
<phrase role="keyword">const</phrase> <phrase role="keyword">unsigned</phrase> <phrase role="identifier">iterations</phrase> <phrase role="special">=</phrase> <phrase role="number">2</phrase><phrase role="special">;</phrase>
<phrase role="keyword">const</phrase> <phrase role="keyword">unsigned</phrase> <phrase role="identifier">clients</phrase> <phrase role="special">=</phrase> <phrase role="number">3</phrase><phrase role="special">;</phrase>
<phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">fibers</phrase><phrase role="special">::</phrase><phrase role="identifier">barrier</phrase> <phrase role="identifier">b</phrase><phrase role="special">(</phrase> <phrase role="identifier">clients</phrase><phrase role="special">);</phrase>
<phrase role="keyword">for</phrase> <phrase role="special">(</phrase> <phrase role="keyword">unsigned</phrase> <phrase role="identifier">i</phrase> <phrase role="special">=</phrase> <phrase role="number">0</phrase><phrase role="special">;</phrase> <phrase role="identifier">i</phrase> <phrase role="special">&lt;</phrase> <phrase role="identifier">clients</phrase><phrase role="special">;</phrase> <phrase role="special">++</phrase><phrase role="identifier">i</phrase><phrase role="special">)</phrase> <phrase role="special">{</phrase>
<phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">fibers</phrase><phrase role="special">::</phrase><phrase role="identifier">fiber</phrase><phrase role="special">(</phrase>
<phrase role="identifier">client</phrase><phrase role="special">,</phrase> <phrase role="identifier">io_svc</phrase><phrase role="special">,</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">ref</phrase><phrase role="special">(</phrase> <phrase role="identifier">a</phrase><phrase role="special">),</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">ref</phrase><phrase role="special">(</phrase> <phrase role="identifier">b</phrase><phrase role="special">),</phrase> <phrase role="identifier">iterations</phrase><phrase role="special">).</phrase><phrase role="identifier">detach</phrase><phrase role="special">();</phrase>
<phrase role="special">}</phrase>
</programlisting>
</para>
<para>
Since we don&#8217;t specify a <link linkend="class_launch"><code>launch</code></link>, these fibers are ready to run,
but have not yet been entered.
</para>
<para>
Having set everything up, the application calls <ulink url="http://www.boost.org/doc/libs/release/doc/html/boost_asio/reference/io_service/run.html"><code><phrase
role="identifier">io_service</phrase><phrase role="special">::</phrase><phrase
role="identifier">run</phrase><phrase role="special">()</phrase></code></ulink>:
</para>
<para>
<programlisting><phrase role="identifier">io_svc</phrase><phrase role="special">-&gt;</phrase><phrase role="identifier">run</phrase><phrase role="special">();</phrase>
</programlisting>
</para>
<para>
Now what?
</para>
<para>
Because this <code><phrase role="identifier">io_service</phrase></code> instance
owns an <code><phrase role="identifier">io_service</phrase><phrase role="special">::</phrase><phrase
role="identifier">work</phrase></code> instance, <code><phrase role="identifier">run</phrase><phrase
role="special">()</phrase></code> does not immediately return. But &mdash; none of
the fibers that will perform actual work has even been entered yet!
</para>
<para>
Without that initial <code><phrase role="identifier">post</phrase><phrase
role="special">()</phrase></code> call in <code><phrase role="identifier">service</phrase></code>&#8217;s
constructor, <emphasis>nothing</emphasis> would happen. The application would
hang right here.
</para>
<para>
So, what should the <code><phrase role="identifier">post</phrase><phrase
role="special">()</phrase></code> handler execute? Simply <link linkend="this_fiber_yield"><code>this_fiber::yield()</code></link>?
</para>
<para>
That would be a promising start. But we have no guarantee that any of the
other fibers will initiate any Asio operations to keep the ball rolling.
For all we know, every other fiber could reach a similar <code><phrase role="identifier">boost</phrase><phrase
role="special">::</phrase><phrase role="identifier">this_fiber</phrase><phrase
role="special">::</phrase><phrase role="identifier">yield</phrase><phrase
role="special">()</phrase></code> call first. Control would return to the
<code><phrase role="identifier">post</phrase><phrase role="special">()</phrase></code>
handler, which would return to Asio, and... the application would hang.
</para>
<para>
The <code><phrase role="identifier">post</phrase><phrase role="special">()</phrase></code>
handler could <code><phrase role="identifier">post</phrase><phrase role="special">()</phrase></code>
itself again. But as discussed in <link linkend="embedded_main_loop">the
previous section</link>, once there are actual I/O operations in flight &mdash; once
we reach a state in which no fiber is ready &mdash;
that would cause the thread to
spin.
</para>
<para>
We could, of course, set an Asio timer &mdash; again as <link linkend="embedded_main_loop">previously
discussed</link>. But in this <quote>deeper dive,</quote> we&#8217;re trying to
do a little better.
</para>
<para>
The key to doing better is that since we&#8217;re in a fiber, we can run an actual
loop &mdash; not just a chain of callbacks. We can wait for <quote>something to happen</quote>
by calling <ulink url="http://www.boost.org/doc/libs/release/doc/html/boost_asio/reference/io_service/run_one.html"><code><phrase
role="identifier">io_service</phrase><phrase role="special">::</phrase><phrase
role="identifier">run_one</phrase><phrase role="special">()</phrase></code></ulink>
&mdash; or we can execute already-queued Asio handlers by calling <ulink url="http://www.boost.org/doc/libs/release/doc/html/boost_asio/reference/io_service/poll.html"><code><phrase
role="identifier">io_service</phrase><phrase role="special">::</phrase><phrase
role="identifier">poll</phrase><phrase role="special">()</phrase></code></ulink>.
</para>
<para>
Here&#8217;s the body of the lambda passed to the <code><phrase role="identifier">post</phrase><phrase
role="special">()</phrase></code> call.
</para>
<para>
<programlisting> <phrase role="keyword">while</phrase> <phrase role="special">(</phrase> <phrase role="special">!</phrase> <phrase role="identifier">io_svc_</phrase><phrase role="special">-&gt;</phrase><phrase role="identifier">stopped</phrase><phrase role="special">()</phrase> <phrase role="special">)</phrase> <phrase role="special">{</phrase>
<phrase role="keyword">if</phrase> <phrase role="special">(</phrase> <phrase role="identifier">has_ready_fibers</phrase><phrase role="special">()</phrase> <phrase role="special">)</phrase> <phrase role="special">{</phrase>
<phrase role="comment">// run all pending handlers in round_robin</phrase>
<phrase role="keyword">while</phrase> <phrase role="special">(</phrase> <phrase role="identifier">io_svc_</phrase><phrase role="special">-&gt;</phrase><phrase role="identifier">poll</phrase><phrase role="special">()</phrase> <phrase role="special">);</phrase>
<phrase role="comment">// block this fiber till all pending (ready) fibers are processed</phrase>
<phrase role="comment">// == round_robin::suspend_until() has been called</phrase>
<phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">unique_lock</phrase><phrase role="special">&lt;</phrase> <phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">fibers</phrase><phrase role="special">::</phrase><phrase role="identifier">mutex</phrase> <phrase role="special">&gt;</phrase> <phrase role="identifier">lk</phrase><phrase role="special">(</phrase> <phrase role="identifier">mtx_</phrase><phrase role="special">);</phrase>
<phrase role="identifier">cnd_</phrase><phrase role="special">.</phrase><phrase role="identifier">wait</phrase><phrase role="special">(</phrase> <phrase role="identifier">lk</phrase><phrase role="special">);</phrase>
<phrase role="special">}</phrase> <phrase role="keyword">else</phrase> <phrase role="special">{</phrase>
<phrase role="comment">// run one handler inside io_service</phrase>
<phrase role="comment">// if no handler available, block this thread</phrase>
<phrase role="keyword">if</phrase> <phrase role="special">(</phrase> <phrase role="special">!</phrase> <phrase role="identifier">io_svc_</phrase><phrase role="special">-&gt;</phrase><phrase role="identifier">run_one</phrase><phrase role="special">()</phrase> <phrase role="special">)</phrase> <phrase role="special">{</phrase>
<phrase role="keyword">break</phrase><phrase role="special">;</phrase>
<phrase role="special">}</phrase>
<phrase role="special">}</phrase>
<phrase role="special">}</phrase>
</programlisting>
</para>
<para>
We want this loop to exit once the <code><phrase role="identifier">io_service</phrase></code>
instance has been <ulink url="http://www.boost.org/doc/libs/release/doc/html/boost_asio/reference/io_service/stopped.html"><code><phrase
role="identifier">stopped</phrase><phrase role="special">()</phrase></code></ulink>.
</para>
<para>
As long as there are ready fibers, we interleave running ready Asio handlers
with running ready fibers.
</para>
<para>
If there are no ready fibers, we wait by calling <code><phrase role="identifier">run_one</phrase><phrase
role="special">()</phrase></code>. Once any Asio handler has been called
&mdash; no matter which &mdash; <code><phrase role="identifier">run_one</phrase><phrase role="special">()</phrase></code>
returns. That handler may have transitioned some fiber to ready state, so
we loop back to check again.
</para>
<para>
(We won&#8217;t describe <code><phrase role="identifier">awakened</phrase><phrase
role="special">()</phrase></code>, <code><phrase role="identifier">pick_next</phrase><phrase
role="special">()</phrase></code> or <code><phrase role="identifier">has_ready_fibers</phrase><phrase
role="special">()</phrase></code>, as these are just like <link linkend="round_robin_awakened"><code>round_robin::awakened()</code></link>,
<link linkend="round_robin_pick_next"><code>round_robin::pick_next()</code></link> and <link linkend="round_robin_has_ready_fibers"><code>round_robin::has_ready_fibers()</code></link>.)
</para>
<para>
That leaves <code><phrase role="identifier">suspend_until</phrase><phrase
role="special">()</phrase></code> and <code><phrase role="identifier">notify</phrase><phrase
role="special">()</phrase></code>.
</para>
<para>
Doubtless you have been asking yourself: why are we calling <code><phrase
role="identifier">io_service</phrase><phrase role="special">::</phrase><phrase
role="identifier">run_one</phrase><phrase role="special">()</phrase></code>
in the lambda loop? Why not call it in <code><phrase role="identifier">suspend_until</phrase><phrase
role="special">()</phrase></code>, whose very API was designed for just such
a purpose?
</para>
<para>
Under normal circumstances, when the fiber manager finds no ready fibers,
it calls <link linkend="algorithm_suspend_until"><code>algorithm::suspend_until()</code></link>. Why test <code><phrase
role="identifier">has_ready_fibers</phrase><phrase role="special">()</phrase></code>
in the lambda loop? Why not leverage the normal mechanism?
</para>
<para>
The answer is: it matters who&#8217;s asking.
</para>
<para>
Consider the lambda loop shown above. The only <emphasis role="bold">Boost.Fiber</emphasis>
APIs it engages are <code><phrase role="identifier">has_ready_fibers</phrase><phrase
role="special">()</phrase></code> and <link linkend="this_fiber_yield"><code>this_fiber::yield()</code></link>.
<code><phrase role="identifier">yield</phrase><phrase role="special">()</phrase></code>
does not <emphasis>block</emphasis> the calling fiber: the calling fiber
does not become unready. It is immediately passed back to <link linkend="algorithm_awakened"><code>algorithm::awakened()</code></link>,
to be resumed in its turn when all other ready fibers have had a chance to
run. In other words: during a <code><phrase role="identifier">yield</phrase><phrase
role="special">()</phrase></code> call, <emphasis>there is always at least
one ready fiber.</emphasis>
</para>
<para>
As long as this lambda loop is still running, the fiber manager does not
call <code><phrase role="identifier">suspend_until</phrase><phrase role="special">()</phrase></code>
because it always has a fiber ready to run.
</para>
<para>
However, the lambda loop <emphasis>itself</emphasis> can detect the case
when no <emphasis>other</emphasis> fibers are ready to run: the running fiber
is not <emphasis>ready</emphasis> but <emphasis>running.</emphasis>
</para>
<para>
That said, <code><phrase role="identifier">suspend_until</phrase><phrase
role="special">()</phrase></code> and <code><phrase role="identifier">notify</phrase><phrase
role="special">()</phrase></code> are in fact called during orderly shutdown
processing, so let&#8217;s try a plausible implementation.
</para>
<para>
<programlisting><phrase role="keyword">void</phrase> <phrase role="identifier">suspend_until</phrase><phrase role="special">(</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">chrono</phrase><phrase role="special">::</phrase><phrase role="identifier">steady_clock</phrase><phrase role="special">::</phrase><phrase role="identifier">time_point</phrase> <phrase role="keyword">const</phrase><phrase role="special">&amp;</phrase> <phrase role="identifier">abs_time</phrase><phrase role="special">)</phrase> <phrase role="keyword">noexcept</phrase> <phrase role="special">{</phrase>
<phrase role="comment">// Set a timer so at least one handler will eventually fire, causing</phrase>
<phrase role="comment">// run_one() to eventually return.</phrase>
<phrase role="keyword">if</phrase> <phrase role="special">(</phrase> <phrase role="special">(</phrase><phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">chrono</phrase><phrase role="special">::</phrase><phrase role="identifier">steady_clock</phrase><phrase role="special">::</phrase><phrase role="identifier">time_point</phrase><phrase role="special">::</phrase><phrase role="identifier">max</phrase><phrase role="special">)()</phrase> <phrase role="special">!=</phrase> <phrase role="identifier">abs_time</phrase><phrase role="special">)</phrase> <phrase role="special">{</phrase>
<phrase role="comment">// Each expires_at(time_point) call cancels any previous pending</phrase>
<phrase role="comment">// call. We could inadvertently spin like this:</phrase>
<phrase role="comment">// dispatcher calls suspend_until() with earliest wake time</phrase>
<phrase role="comment">// suspend_until() sets suspend_timer_</phrase>
<phrase role="comment">// lambda loop calls run_one()</phrase>
<phrase role="comment">// some other asio handler runs before timer expires</phrase>
<phrase role="comment">// run_one() returns to lambda loop</phrase>
<phrase role="comment">// lambda loop yields to dispatcher</phrase>
<phrase role="comment">// dispatcher finds no ready fibers</phrase>
<phrase role="comment">// dispatcher calls suspend_until() with SAME wake time</phrase>
<phrase role="comment">// suspend_until() sets suspend_timer_ to same time, canceling</phrase>
<phrase role="comment">// previous async_wait()</phrase>
<phrase role="comment">// lambda loop calls run_one()</phrase>
<phrase role="comment">// asio calls suspend_timer_ handler with operation_aborted</phrase>
<phrase role="comment">// run_one() returns to lambda loop... etc. etc.</phrase>
<phrase role="comment">// So only actually set the timer when we're passed a DIFFERENT</phrase>
<phrase role="comment">// abs_time value.</phrase>
<phrase role="identifier">suspend_timer_</phrase><phrase role="special">.</phrase><phrase role="identifier">expires_at</phrase><phrase role="special">(</phrase> <phrase role="identifier">abs_time</phrase><phrase role="special">);</phrase>
<phrase role="identifier">suspend_timer_</phrase><phrase role="special">.</phrase><phrase role="identifier">async_wait</phrase><phrase role="special">([](</phrase><phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">system</phrase><phrase role="special">::</phrase><phrase role="identifier">error_code</phrase> <phrase role="keyword">const</phrase><phrase role="special">&amp;){</phrase>
<phrase role="identifier">this_fiber</phrase><phrase role="special">::</phrase><phrase role="identifier">yield</phrase><phrase role="special">();</phrase>
<phrase role="special">});</phrase>
<phrase role="special">}</phrase>
<phrase role="identifier">cnd_</phrase><phrase role="special">.</phrase><phrase role="identifier">notify_one</phrase><phrase role="special">();</phrase>
<phrase role="special">}</phrase>
</programlisting>
</para>
<para>
As you might expect, <code><phrase role="identifier">suspend_until</phrase><phrase
role="special">()</phrase></code> sets an <ulink url="http://www.boost.org/doc/libs/release/doc/html/boost_asio/reference/steady_timer.html"><code><phrase
role="identifier">asio</phrase><phrase role="special">::</phrase><phrase
role="identifier">steady_timer</phrase></code></ulink> to <ulink url="http://www.boost.org/doc/libs/release/doc/html/boost_asio/reference/basic_waitable_timer/expires_at.html"><code><phrase
role="identifier">expires_at</phrase><phrase role="special">()</phrase></code></ulink>
the passed <ulink url="http://en.cppreference.com/w/cpp/chrono/steady_clock"><code><phrase
role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">chrono</phrase><phrase
role="special">::</phrase><phrase role="identifier">steady_clock</phrase><phrase
role="special">::</phrase><phrase role="identifier">time_point</phrase></code></ulink>.
Usually.
</para>
<para>
As indicated in comments, we avoid setting <code><phrase role="identifier">suspend_timer_</phrase></code>
multiple times to the <emphasis>same</emphasis> <code><phrase role="identifier">time_point</phrase></code>
value since every <code><phrase role="identifier">expires_at</phrase><phrase
role="special">()</phrase></code> call cancels any previous <ulink url="http://www.boost.org/doc/libs/release/doc/html/boost_asio/reference/basic_waitable_timer/async_wait.html"><code><phrase
role="identifier">async_wait</phrase><phrase role="special">()</phrase></code></ulink>
call. There is a chance that we could spin. Reaching <code><phrase role="identifier">suspend_until</phrase><phrase
role="special">()</phrase></code> means the fiber manager intends to yield
the processor to Asio. Cancelling the previous <code><phrase role="identifier">async_wait</phrase><phrase
role="special">()</phrase></code> call would fire its handler, causing <code><phrase
role="identifier">run_one</phrase><phrase role="special">()</phrase></code>
to return, potentially causing the fiber manager to call <code><phrase role="identifier">suspend_until</phrase><phrase
role="special">()</phrase></code> again with the same <code><phrase role="identifier">time_point</phrase></code>
value...
</para>
<para>
Given that we suspend the thread by calling <code><phrase role="identifier">io_service</phrase><phrase
role="special">::</phrase><phrase role="identifier">run_one</phrase><phrase
role="special">()</phrase></code>, what&#8217;s important is that our <code><phrase
role="identifier">async_wait</phrase><phrase role="special">()</phrase></code>
call will cause a handler to run, which will cause <code><phrase role="identifier">run_one</phrase><phrase
role="special">()</phrase></code> to return. It&#8217;s not so important specifically
what that handler does.
</para>
<para>
<programlisting><phrase role="keyword">void</phrase> <phrase role="identifier">notify</phrase><phrase role="special">()</phrase> <phrase role="keyword">noexcept</phrase> <phrase role="special">{</phrase>
<phrase role="comment">// Something has happened that should wake one or more fibers BEFORE</phrase>
<phrase role="comment">// suspend_timer_ expires. Reset the timer to cause it to fire</phrase>
<phrase role="comment">// immediately, causing the run_one() call to return. In theory we</phrase>
<phrase role="comment">// could use cancel() because we don't care whether suspend_timer_'s</phrase>
<phrase role="comment">// handler is called with operation_aborted or success. However --</phrase>
<phrase role="comment">// cancel() doesn't change the expiration time, and we use</phrase>
<phrase role="comment">// suspend_timer_'s expiration time to decide whether it's already</phrase>
<phrase role="comment">// set. If suspend_until() set some specific wake time, then notify()</phrase>
<phrase role="comment">// canceled it, then suspend_until() was called again with the same</phrase>
<phrase role="comment">// wake time, it would match suspend_timer_'s expiration time and we'd</phrase>
<phrase role="comment">// refrain from setting the timer. So instead of simply calling</phrase>
<phrase role="comment">// cancel(), reset the timer, which cancels the pending sleep AND sets</phrase>
<phrase role="comment">// a new expiration time. This will cause us to spin the loop twice --</phrase>
<phrase role="comment">// once for the operation_aborted handler, once for timer expiration</phrase>
<phrase role="comment">// -- but that shouldn't be a big problem.</phrase>
<phrase role="identifier">suspend_timer_</phrase><phrase role="special">.</phrase><phrase role="identifier">async_wait</phrase><phrase role="special">([](</phrase><phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">system</phrase><phrase role="special">::</phrase><phrase role="identifier">error_code</phrase> <phrase role="keyword">const</phrase><phrase role="special">&amp;){</phrase>
<phrase role="identifier">this_fiber</phrase><phrase role="special">::</phrase><phrase role="identifier">yield</phrase><phrase role="special">();</phrase>
<phrase role="special">});</phrase>
<phrase role="identifier">suspend_timer_</phrase><phrase role="special">.</phrase><phrase role="identifier">expires_at</phrase><phrase role="special">(</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">chrono</phrase><phrase role="special">::</phrase><phrase role="identifier">steady_clock</phrase><phrase role="special">::</phrase><phrase role="identifier">now</phrase><phrase role="special">()</phrase> <phrase role="special">);</phrase>
<phrase role="special">}</phrase>
</programlisting>
</para>
<para>
Since an <code><phrase role="identifier">expires_at</phrase><phrase role="special">()</phrase></code>
call cancels any previous <code><phrase role="identifier">async_wait</phrase><phrase
role="special">()</phrase></code> call, we can make <code><phrase role="identifier">notify</phrase><phrase
role="special">()</phrase></code> simply call <code><phrase role="identifier">steady_timer</phrase><phrase
role="special">::</phrase><phrase role="identifier">expires_at</phrase><phrase
role="special">()</phrase></code>. That should cause the <code><phrase role="identifier">io_service</phrase></code>
to call the <code><phrase role="identifier">async_wait</phrase><phrase role="special">()</phrase></code>
handler with <code><phrase role="identifier">operation_aborted</phrase></code>.
</para>
<para>
The comments in <code><phrase role="identifier">notify</phrase><phrase role="special">()</phrase></code>
explain why we call <code><phrase role="identifier">expires_at</phrase><phrase
role="special">()</phrase></code> rather than <ulink url="http://www.boost.org/doc/libs/release/doc/html/boost_asio/reference/basic_waitable_timer/cancel.html"><code><phrase
role="identifier">cancel</phrase><phrase role="special">()</phrase></code></ulink>.
</para>
<para>
This <code><phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase
role="identifier">fibers</phrase><phrase role="special">::</phrase><phrase
role="identifier">asio</phrase><phrase role="special">::</phrase><phrase
role="identifier">round_robin</phrase></code> implementation is used in
<ulink url="../../examples/asio/autoecho.cpp"><code><phrase role="identifier">examples</phrase><phrase
role="special">/</phrase><phrase role="identifier">asio</phrase><phrase role="special">/</phrase><phrase
role="identifier">autoecho</phrase><phrase role="special">.</phrase><phrase
role="identifier">cpp</phrase></code></ulink>.
</para>
<para>
It seems possible that you could put together a more elegant Fiber / Asio
integration. But as noted at the outset: it&#8217;s tricky.
</para>
</section>
</section>
<section id="fiber.speculation">
<title><anchor id="speculation"/><link linkend="fiber.speculation">Specualtive
execution</link></title>
<bridgehead renderas="sect3" id="fiber.speculation.h0">
<phrase id="fiber.speculation.hardware_transactional_memory"/><link linkend="fiber.speculation.hardware_transactional_memory">Hardware
transactional memory</link>
</bridgehead>
<para>
With help of hardware transactional memory multiple logical processors execute
a critical region speculatively, e.g. without explicit synchronization.<sbr/>
If the transactional execution completes successfully, then all memory operations
performed within the transactional region are commited without any inter-thread
serialization.<sbr/> When the optimistic execution fails, the processor aborts
the transaction and discards all performed modifications.<sbr/> In non-transactional
code a single lock serializes the access to a critical region. With a transactional
memory, multiple logical processor start a transaction and update the memory
(the data) inside the ciritical region. Unless some logical processors try
to update the same data, the transactions would always succeed.
</para>
<bridgehead renderas="sect3" id="fiber.speculation.h1">
<phrase id="fiber.speculation.intel_transactional_synchronisation_extensions__tsx_"/><link
linkend="fiber.speculation.intel_transactional_synchronisation_extensions__tsx_">Intel
Transactional Synchronisation Extensions (TSX)</link>
</bridgehead>
<para>
TSX is Intel's implementation of hardware transactional memory in modern Intel
processors<footnote id="fiber.speculation.f0">
<para>
intel.com: <ulink url="https://software.intel.com/en-us/node/695149">Intel
Transactional Synchronization Extensions</ulink>
</para>
</footnote>.<sbr/> In TSX the hardware keeps track of which cachelines have
been read from and which have been written to in a transaction. The cache-line
size (64-byte) and the n-way set associative cache determine the maximum size
of memory in a transaction. For instance if a transaction modifies 9 cache-lines
at a processor with a 8-way set associative cache, the transaction will always
be aborted.
</para>
<note>
<para>
TXS is enabled if property <code><phrase role="identifier">htm</phrase><phrase
role="special">=</phrase><phrase role="identifier">tsx</phrase></code> is
specified at b2 command-line and <code><phrase role="identifier">BOOST_USE_TSX</phrase></code>
is applied to the compiler.
</para>
</note>
<note>
<para>
A TSX-transaction will be aborted if the floating point state is modified
inside a critical region. As a consequence floating point operations, e.g.
store/load of floating point related registers during a fiber (context) switch
are disabled.
</para>
</note>
<important>
<para>
TSX can not be used together with MSVC at this time!
</para>
</important>
<para>
Boost.Fiber uses TSX-enabled spinlocks to protect critical regions (see section
<link linkend="tuning">Tuning</link>).
</para>
</section>
<section id="fiber.numa">
<title><anchor id="numa"/><link linkend="fiber.numa">NUMA</link></title>
<para>
Modern micro-processors contain integrated memory controllers that are connected
via channels to the memory. Accessing the memory can be organized in two kinds:<sbr/>
Uniform Memory Access (UMA) and Non-Uniform Memory Access (NUMA).
</para>
<para>
In contrast to UMA, that provides a centralized pool of memory (and thus does
not scale after a certain number of processors), a NUMA architecture divides
the memory into local and remote memory relative to the micro-processor.<sbr/>
Local memory is directly attached to the processor's integrated memory controller.
Memory connected to the memory controller of another micro-processor (multi-socket
systems) is considered as remote memory. If a memory controller access remote
memory it has to traverse the interconnect<footnote id="fiber.numa.f0">
<para>
On x86 the interconnection is implemented by Intel's Quick Path Interconnect
(QPI) and AMD's HyperTransport.
</para>
</footnote> and connect to the remote memory controller.<sbr/> Thus accessing
remote memory adds additional latency overhead to local memory access. Because
of the different memory locations, a NUMA-system experiences <emphasis>non-uniform</emphasis>
memory access time.<sbr/> As a consequence the best performance is achieved
by keeping the memory access local.
</para>
<para>
<inlinemediaobject><imageobject><imagedata align="center" fileref="../../../../libs/fiber/doc/NUMA.png"></imagedata></imageobject>
<textobject>
<phrase>NUMA</phrase>
</textobject>
</inlinemediaobject>
</para>
<bridgehead renderas="sect3" id="fiber.numa.h0">
<phrase id="fiber.numa.numa_support_in_boost_fiber"/><link linkend="fiber.numa.numa_support_in_boost_fiber">NUMA
support in Boost.Fiber</link>
</bridgehead>
<para>
Because only a subset of the NUMA-functionality is exposed by several operating
systems, Boost.Fiber provides only a minimalistic NUMA API.
</para>
<important>
<para>
In order to enable NUMA support, b2 property <code><phrase role="identifier">numa</phrase><phrase
role="special">=</phrase><phrase role="identifier">on</phrase></code> must
be specified and linked against additional library <code><phrase role="identifier">libboost_fiber_numa</phrase><phrase
role="special">.</phrase><phrase role="identifier">so</phrase></code>.
</para>
</important>
<important>
<para>
MinGW using pthread implementation is not supported on Windows.
</para>
</important>
<table frame="all" id="fiber.numa.supported_functionality_operating_systems">
<title>Supported functionality/operating systems</title>
<tgroup cols="7">
<thead>
<row>
<entry>
</entry>
<entry>
<para>
AIX
</para>
</entry>
<entry>
<para>
FreeBSD
</para>
</entry>
<entry>
<para>
HP/UX
</para>
</entry>
<entry>
<para>
Linux
</para>
</entry>
<entry>
<para>
Solaris
</para>
</entry>
<entry>
<para>
Windows
</para>
</entry>
</row>
</thead>
<tbody>
<row>
<entry>
<para>
pin thread
</para>
</entry>
<entry>
<para>
+
</para>
</entry>
<entry>
<para>
+
</para>
</entry>
<entry>
<para>
+
</para>
</entry>
<entry>
<para>
+
</para>
</entry>
<entry>
<para>
+
</para>
</entry>
<entry>
<para>
+
</para>
</entry>
</row>
<row>
<entry>
<para>
logical CPUs/NUMA nodes
</para>
</entry>
<entry>
<para>
+
</para>
</entry>
<entry>
<para>
+
</para>
</entry>
<entry>
<para>
+
</para>
</entry>
<entry>
<para>
+
</para>
</entry>
<entry>
<para>
+
</para>
</entry>
<entry>
<para>
+<footnote id="fiber.numa.f1">
<para>
Windows organizes logical cpus in groups of 64; boost.fiber maps
{group-id,cpud-id} to a scalar equivalent to cpu ID of Linux (64
* group ID + cpu ID).
</para>
</footnote>
</para>
</entry>
</row>
<row>
<entry>
<para>
NUMA node distance
</para>
</entry>
<entry>
<para>
-
</para>
</entry>
<entry>
<para>
-
</para>
</entry>
<entry>
<para>
-
</para>
</entry>
<entry>
<para>
+
</para>
</entry>
<entry>
<para>
-
</para>
</entry>
<entry>
<para>
-
</para>
</entry>
</row>
<row>
<entry>
<para>
tested on
</para>
</entry>
<entry>
<para>
AIX 7.2
</para>
</entry>
<entry>
<para>
FreeBSD 11
</para>
</entry>
<entry>
<para>
-
</para>
</entry>
<entry>
<para>
Arch Linux (4.10.13)
</para>
</entry>
<entry>
<para>
OpenIndiana HIPSTER
</para>
</entry>
<entry>
<para>
Windows 10
</para>
</entry>
</row>
</tbody>
</tgroup>
</table>
<para>
In order to keep the memory access local as possible, the NUMA topology must
be evaluated.
</para>
<programlisting><phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">vector</phrase><phrase role="special">&lt;</phrase> <phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">fibers</phrase><phrase role="special">::</phrase><phrase role="identifier">numa</phrase><phrase role="special">::</phrase><phrase role="identifier">node</phrase> <phrase role="special">&gt;</phrase> <phrase role="identifier">topo</phrase> <phrase role="special">=</phrase> <phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">fibers</phrase><phrase role="special">::</phrase><phrase role="identifier">numa</phrase><phrase role="special">::</phrase><phrase role="identifier">topology</phrase><phrase role="special">();</phrase>
<phrase role="keyword">for</phrase> <phrase role="special">(</phrase> <phrase role="keyword">auto</phrase> <phrase role="identifier">n</phrase> <phrase role="special">:</phrase> <phrase role="identifier">topo</phrase><phrase role="special">)</phrase> <phrase role="special">{</phrase>
<phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">cout</phrase> <phrase role="special">&lt;&lt;</phrase> <phrase role="string">&quot;node: &quot;</phrase> <phrase role="special">&lt;&lt;</phrase> <phrase role="identifier">n</phrase><phrase role="special">.</phrase><phrase role="identifier">id</phrase> <phrase role="special">&lt;&lt;</phrase> <phrase role="string">&quot; | &quot;</phrase><phrase role="special">;</phrase>
<phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">cout</phrase> <phrase role="special">&lt;&lt;</phrase> <phrase role="string">&quot;cpus: &quot;</phrase><phrase role="special">;</phrase>
<phrase role="keyword">for</phrase> <phrase role="special">(</phrase> <phrase role="keyword">auto</phrase> <phrase role="identifier">cpu_id</phrase> <phrase role="special">:</phrase> <phrase role="identifier">n</phrase><phrase role="special">.</phrase><phrase role="identifier">logical_cpus</phrase><phrase role="special">)</phrase> <phrase role="special">{</phrase>
<phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">cout</phrase> <phrase role="special">&lt;&lt;</phrase> <phrase role="identifier">cpu_id</phrase> <phrase role="special">&lt;&lt;</phrase> <phrase role="string">&quot; &quot;</phrase><phrase role="special">;</phrase>
<phrase role="special">}</phrase>
<phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">cout</phrase> <phrase role="special">&lt;&lt;</phrase> <phrase role="string">&quot;| distance: &quot;</phrase><phrase role="special">;</phrase>
<phrase role="keyword">for</phrase> <phrase role="special">(</phrase> <phrase role="keyword">auto</phrase> <phrase role="identifier">d</phrase> <phrase role="special">:</phrase> <phrase role="identifier">n</phrase><phrase role="special">.</phrase><phrase role="identifier">distance</phrase><phrase role="special">)</phrase> <phrase role="special">{</phrase>
<phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">cout</phrase> <phrase role="special">&lt;&lt;</phrase> <phrase role="identifier">d</phrase> <phrase role="special">&lt;&lt;</phrase> <phrase role="string">&quot; &quot;</phrase><phrase role="special">;</phrase>
<phrase role="special">}</phrase>
<phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">cout</phrase> <phrase role="special">&lt;&lt;</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">endl</phrase><phrase role="special">;</phrase>
<phrase role="special">}</phrase>
<phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">cout</phrase> <phrase role="special">&lt;&lt;</phrase> <phrase role="string">&quot;done&quot;</phrase> <phrase role="special">&lt;&lt;</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">endl</phrase><phrase role="special">;</phrase>
<phrase role="identifier">output</phrase><phrase role="special">:</phrase>
<phrase role="identifier">node</phrase><phrase role="special">:</phrase> <phrase role="number">0</phrase> <phrase role="special">|</phrase> <phrase role="identifier">cpus</phrase><phrase role="special">:</phrase> <phrase role="number">0</phrase> <phrase role="number">1</phrase> <phrase role="number">2</phrase> <phrase role="number">3</phrase> <phrase role="number">4</phrase> <phrase role="number">5</phrase> <phrase role="number">6</phrase> <phrase role="number">7</phrase> <phrase role="number">16</phrase> <phrase role="number">17</phrase> <phrase role="number">18</phrase> <phrase role="number">19</phrase> <phrase role="number">20</phrase> <phrase role="number">21</phrase> <phrase role="number">22</phrase> <phrase role="number">23</phrase> <phrase role="special">|</phrase> <phrase role="identifier">distance</phrase><phrase role="special">:</phrase> <phrase role="number">10</phrase> <phrase role="number">21</phrase>
<phrase role="identifier">node</phrase><phrase role="special">:</phrase> <phrase role="number">1</phrase> <phrase role="special">|</phrase> <phrase role="identifier">cpus</phrase><phrase role="special">:</phrase> <phrase role="number">8</phrase> <phrase role="number">9</phrase> <phrase role="number">10</phrase> <phrase role="number">11</phrase> <phrase role="number">12</phrase> <phrase role="number">13</phrase> <phrase role="number">14</phrase> <phrase role="number">15</phrase> <phrase role="number">24</phrase> <phrase role="number">25</phrase> <phrase role="number">26</phrase> <phrase role="number">27</phrase> <phrase role="number">28</phrase> <phrase role="number">29</phrase> <phrase role="number">30</phrase> <phrase role="number">31</phrase> <phrase role="special">|</phrase> <phrase role="identifier">distance</phrase><phrase role="special">:</phrase> <phrase role="number">21</phrase> <phrase role="number">10</phrase>
<phrase role="identifier">done</phrase>
</programlisting>
<para>
The example shows that the systems consits out of 2 NUMA-nodes, to each NUMA-node
belong 16 logical cpus. The distance measures the costs to access the memory
of another NUMA-node. A NUMA-node has always a distance <code><phrase role="number">10</phrase></code>
to itself (lowest possible value).<sbr/> The position in the array corresponds
with the NUMA-node ID.
</para>
<para>
Some work-loads benefit from pinning threads to a logical cpus. For instance
scheduling algorithm <link linkend="class_numa_work_stealing"><code>numa::work_stealing</code></link> pins the thread
that runs the fiber scheduler to a logical cpu. This prevents the operating
system scheduler to move the thread to another logical cpu that might run other
fiber scheduler(s) or migrating the thread to a logical cpu part of another
NUMA-node.
</para>
<programlisting><phrase role="keyword">void</phrase> <phrase role="identifier">thread</phrase><phrase role="special">(</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">uint32_t</phrase> <phrase role="identifier">cpu_id</phrase><phrase role="special">,</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">uint32_t</phrase> <phrase role="identifier">node_id</phrase><phrase role="special">,</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">vector</phrase><phrase role="special">&lt;</phrase> <phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">fibers</phrase><phrase role="special">::</phrase><phrase role="identifier">numa</phrase><phrase role="special">::</phrase><phrase role="identifier">node</phrase> <phrase role="special">&gt;</phrase> <phrase role="keyword">const</phrase><phrase role="special">&amp;</phrase> <phrase role="identifier">topo</phrase><phrase role="special">)</phrase> <phrase role="special">{</phrase>
<phrase role="comment">// thread registers itself at work-stealing scheduler</phrase>
<phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">fibers</phrase><phrase role="special">::</phrase><phrase role="identifier">use_scheduling_algorithm</phrase><phrase role="special">&lt;</phrase> <phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">fibers</phrase><phrase role="special">::</phrase><phrase role="identifier">algo</phrase><phrase role="special">::</phrase><phrase role="identifier">numa</phrase><phrase role="special">::</phrase><phrase role="identifier">work_stealing</phrase> <phrase role="special">&gt;(</phrase> <phrase role="identifier">cpu_id</phrase><phrase role="special">,</phrase> <phrase role="identifier">node_id</phrase><phrase role="special">,</phrase> <phrase role="identifier">topo</phrase><phrase role="special">);</phrase>
<phrase role="special">...</phrase>
<phrase role="special">}</phrase>
<phrase role="comment">// evaluate the NUMA topology</phrase>
<phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">vector</phrase><phrase role="special">&lt;</phrase> <phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">fibers</phrase><phrase role="special">::</phrase><phrase role="identifier">numa</phrase><phrase role="special">::</phrase><phrase role="identifier">node</phrase> <phrase role="special">&gt;</phrase> <phrase role="identifier">topo</phrase> <phrase role="special">=</phrase> <phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">fibers</phrase><phrase role="special">::</phrase><phrase role="identifier">numa</phrase><phrase role="special">::</phrase><phrase role="identifier">topology</phrase><phrase role="special">();</phrase>
<phrase role="comment">// start-thread runs on NUMA-node `0`</phrase>
<phrase role="keyword">auto</phrase> <phrase role="identifier">node</phrase> <phrase role="special">=</phrase> <phrase role="identifier">topo</phrase><phrase role="special">[</phrase><phrase role="number">0</phrase><phrase role="special">];</phrase>
<phrase role="comment">// start-thread is pinnded to first cpu ID in the list of logical cpus of NUMA-node `0`</phrase>
<phrase role="keyword">auto</phrase> <phrase role="identifier">start_cpu_id</phrase> <phrase role="special">=</phrase> <phrase role="special">*</phrase> <phrase role="identifier">node</phrase><phrase role="special">.</phrase><phrase role="identifier">logical_cpus</phrase><phrase role="special">.</phrase><phrase role="identifier">begin</phrase><phrase role="special">();</phrase>
<phrase role="comment">// start worker-threads first</phrase>
<phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">vector</phrase><phrase role="special">&lt;</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">thread</phrase> <phrase role="special">&gt;</phrase> <phrase role="identifier">threads</phrase><phrase role="special">;</phrase>
<phrase role="keyword">for</phrase> <phrase role="special">(</phrase> <phrase role="keyword">auto</phrase> <phrase role="special">&amp;</phrase> <phrase role="identifier">node</phrase> <phrase role="special">:</phrase> <phrase role="identifier">topo</phrase><phrase role="special">)</phrase> <phrase role="special">{</phrase>
<phrase role="keyword">for</phrase> <phrase role="special">(</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">uint32_t</phrase> <phrase role="identifier">cpu_id</phrase> <phrase role="special">:</phrase> <phrase role="identifier">node</phrase><phrase role="special">.</phrase><phrase role="identifier">logical_cpus</phrase><phrase role="special">)</phrase> <phrase role="special">{</phrase>
<phrase role="comment">// exclude start-thread</phrase>
<phrase role="keyword">if</phrase> <phrase role="special">(</phrase> <phrase role="identifier">start_cpu_id</phrase> <phrase role="special">!=</phrase> <phrase role="identifier">cpu_id</phrase><phrase role="special">)</phrase> <phrase role="special">{</phrase>
<phrase role="comment">// spawn thread</phrase>
<phrase role="identifier">threads</phrase><phrase role="special">.</phrase><phrase role="identifier">emplace_back</phrase><phrase role="special">(</phrase> <phrase role="identifier">thread</phrase><phrase role="special">,</phrase> <phrase role="identifier">cpu_id</phrase><phrase role="special">,</phrase> <phrase role="identifier">node</phrase><phrase role="special">.</phrase><phrase role="identifier">id</phrase><phrase role="special">,</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">cref</phrase><phrase role="special">(</phrase> <phrase role="identifier">topo</phrase><phrase role="special">)</phrase> <phrase role="special">);</phrase>
<phrase role="special">}</phrase>
<phrase role="special">}</phrase>
<phrase role="special">}</phrase>
<phrase role="comment">// start-thread registers itself on work-stealing scheduler</phrase>
<phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">fibers</phrase><phrase role="special">::</phrase><phrase role="identifier">use_scheduling_algorithm</phrase><phrase role="special">&lt;</phrase> <phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">fibers</phrase><phrase role="special">::</phrase><phrase role="identifier">algo</phrase><phrase role="special">::</phrase><phrase role="identifier">numa</phrase><phrase role="special">::</phrase><phrase role="identifier">work_stealing</phrase> <phrase role="special">&gt;(</phrase> <phrase role="identifier">start_cpu_id</phrase><phrase role="special">,</phrase> <phrase role="identifier">node</phrase><phrase role="special">.</phrase><phrase role="identifier">id</phrase><phrase role="special">,</phrase> <phrase role="identifier">topo</phrase><phrase role="special">);</phrase>
<phrase role="special">...</phrase>
</programlisting>
<para>
The example evaluates the NUMA topology with <code><phrase role="identifier">boost</phrase><phrase
role="special">::</phrase><phrase role="identifier">fibers</phrase><phrase
role="special">::</phrase><phrase role="identifier">numa</phrase><phrase role="special">::</phrase><phrase
role="identifier">topology</phrase><phrase role="special">()</phrase></code>
and spawns for each logical cpu a thread. Each spawned thread installs the
NUMA-aware work-stealing scheduler. The scheduler pins the thread to the logical
cpu that was specified at construction.<sbr/> If the local queue of one thread
runs out of ready fibers, the thread tries to steal a ready fiber from another
thread running at logical cpu that belong to the same NUMA-node (local memory
access). If no fiber could be stolen, the thread tries to steal fibers from
logical cpus part of other NUMA-nodes (remote memory access).
</para>
<bridgehead renderas="sect3" id="fiber.numa.h1">
<phrase id="fiber.numa.synopsis"/><link linkend="fiber.numa.synopsis">Synopsis</link>
</bridgehead>
<programlisting><phrase role="preprocessor">#include</phrase> <phrase role="special">&lt;</phrase><phrase role="identifier">boost</phrase><phrase role="special">/</phrase><phrase role="identifier">fiber</phrase><phrase role="special">/</phrase><phrase role="identifier">numa</phrase><phrase role="special">/</phrase><phrase role="identifier">pin_thread</phrase><phrase role="special">.</phrase><phrase role="identifier">hpp</phrase><phrase role="special">&gt;</phrase>
<phrase role="preprocessor">#include</phrase> <phrase role="special">&lt;</phrase><phrase role="identifier">boost</phrase><phrase role="special">/</phrase><phrase role="identifier">fiber</phrase><phrase role="special">/</phrase><phrase role="identifier">numa</phrase><phrase role="special">/</phrase><phrase role="identifier">topology</phrase><phrase role="special">.</phrase><phrase role="identifier">hpp</phrase><phrase role="special">&gt;</phrase>
<phrase role="keyword">namespace</phrase> <phrase role="identifier">boost</phrase> <phrase role="special">{</phrase>
<phrase role="keyword">namespace</phrase> <phrase role="identifier">fibers</phrase> <phrase role="special">{</phrase>
<phrase role="keyword">namespace</phrase> <phrase role="identifier">numa</phrase> <phrase role="special">{</phrase>
<phrase role="keyword">struct</phrase> <phrase role="identifier">node</phrase> <phrase role="special">{</phrase>
<phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">uint32_t</phrase> <phrase role="identifier">id</phrase><phrase role="special">;</phrase>
<phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">set</phrase><phrase role="special">&lt;</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">uint32_t</phrase> <phrase role="special">&gt;</phrase> <phrase role="identifier">logical_cpus</phrase><phrase role="special">;</phrase>
<phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">vector</phrase><phrase role="special">&lt;</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">uint32_t</phrase> <phrase role="special">&gt;</phrase> <phrase role="identifier">distance</phrase><phrase role="special">;</phrase>
<phrase role="special">};</phrase>
<phrase role="keyword">bool</phrase> <phrase role="keyword">operator</phrase><phrase role="special">&lt;(</phrase> <phrase role="identifier">node</phrase> <phrase role="keyword">const</phrase><phrase role="special">&amp;,</phrase> <phrase role="identifier">node</phrase> <phrase role="keyword">const</phrase><phrase role="special">&amp;)</phrase> <phrase role="keyword">noexcept</phrase><phrase role="special">;</phrase>
<phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">vector</phrase><phrase role="special">&lt;</phrase> <phrase role="identifier">node</phrase> <phrase role="special">&gt;</phrase> <phrase role="identifier">topology</phrase><phrase role="special">();</phrase>
<phrase role="keyword">void</phrase> <phrase role="identifier">pin_thread</phrase><phrase role="special">(</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">uint32_t</phrase><phrase role="special">);</phrase>
<phrase role="keyword">void</phrase> <phrase role="identifier">pin_thread</phrase><phrase role="special">(</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">uint32_t</phrase><phrase role="special">,</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">thread</phrase><phrase role="special">::</phrase><phrase role="identifier">native_handle_type</phrase><phrase role="special">);</phrase>
<phrase role="special">}}}</phrase>
<phrase role="preprocessor">#include</phrase> <phrase role="special">&lt;</phrase><phrase role="identifier">boost</phrase><phrase role="special">/</phrase><phrase role="identifier">fiber</phrase><phrase role="special">/</phrase><phrase role="identifier">numa</phrase><phrase role="special">/</phrase><phrase role="identifier">algo</phrase><phrase role="special">/</phrase><phrase role="identifier">work_stealing</phrase><phrase role="special">.</phrase><phrase role="identifier">hpp</phrase><phrase role="special">&gt;</phrase>
<phrase role="keyword">namespace</phrase> <phrase role="identifier">boost</phrase> <phrase role="special">{</phrase>
<phrase role="keyword">namespace</phrase> <phrase role="identifier">fibers</phrase> <phrase role="special">{</phrase>
<phrase role="keyword">namespace</phrase> <phrase role="identifier">numa</phrase> <phrase role="special">{</phrase>
<phrase role="keyword">namespace</phrase> <phrase role="identifier">algo</phrase> <phrase role="special">{</phrase>
<phrase role="keyword">class</phrase> <phrase role="identifier">work_stealing</phrase><phrase role="special">;</phrase>
<phrase role="special">}}}</phrase>
</programlisting>
<para>
<bridgehead renderas="sect4" id="class_numa_node_bridgehead">
<phrase id="class_numa_node"/>
<link linkend="class_numa_node">Class <code>numa::node</code></link>
</bridgehead>
</para>
<programlisting><phrase role="preprocessor">#include</phrase> <phrase role="special">&lt;</phrase><phrase role="identifier">boost</phrase><phrase role="special">/</phrase><phrase role="identifier">fiber</phrase><phrase role="special">/</phrase><phrase role="identifier">numa</phrase><phrase role="special">/</phrase><phrase role="identifier">topology</phrase><phrase role="special">.</phrase><phrase role="identifier">hpp</phrase><phrase role="special">&gt;</phrase>
<phrase role="keyword">namespace</phrase> <phrase role="identifier">boost</phrase> <phrase role="special">{</phrase>
<phrase role="keyword">namespace</phrase> <phrase role="identifier">fibers</phrase> <phrase role="special">{</phrase>
<phrase role="keyword">namespace</phrase> <phrase role="identifier">numa</phrase> <phrase role="special">{</phrase>
<phrase role="keyword">struct</phrase> <phrase role="identifier">node</phrase> <phrase role="special">{</phrase>
<phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">uint32_t</phrase> <phrase role="identifier">id</phrase><phrase role="special">;</phrase>
<phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">set</phrase><phrase role="special">&lt;</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">uint32_t</phrase> <phrase role="special">&gt;</phrase> <phrase role="identifier">logical_cpus</phrase><phrase role="special">;</phrase>
<phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">vector</phrase><phrase role="special">&lt;</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">uint32_t</phrase> <phrase role="special">&gt;</phrase> <phrase role="identifier">distance</phrase><phrase role="special">;</phrase>
<phrase role="special">};</phrase>
<phrase role="keyword">bool</phrase> <phrase role="keyword">operator</phrase><phrase role="special">&lt;(</phrase> <phrase role="identifier">node</phrase> <phrase role="keyword">const</phrase><phrase role="special">&amp;,</phrase> <phrase role="identifier">node</phrase> <phrase role="keyword">const</phrase><phrase role="special">&amp;)</phrase> <phrase role="keyword">noexcept</phrase><phrase role="special">;</phrase>
<phrase role="special">}}}</phrase>
</programlisting>
<para>
<bridgehead renderas="sect4" id="numa_node_id_bridgehead">
<phrase id="numa_node_id"/>
<link linkend="numa_node_id">Data member <code>id</code></link>
</bridgehead>
</para>
<programlisting><phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">uint32_t</phrase> <phrase role="identifier">id</phrase><phrase role="special">;</phrase>
</programlisting>
<variablelist>
<title></title>
<varlistentry>
<term>Effects:</term>
<listitem>
<para>
ID of the NUMA-node
</para>
</listitem>
</varlistentry>
</variablelist>
<para>
<bridgehead renderas="sect4" id="numa_node_logical_cpus_bridgehead">
<phrase id="numa_node_logical_cpus"/>
<link linkend="numa_node_logical_cpus">Data
member <code>logical_cpus</code></link>
</bridgehead>
</para>
<programlisting><phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">set</phrase><phrase role="special">&lt;</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">uint32_t</phrase> <phrase role="special">&gt;</phrase> <phrase role="identifier">logical_cpus</phrase><phrase role="special">;</phrase>
</programlisting>
<variablelist>
<title></title>
<varlistentry>
<term>Effects:</term>
<listitem>
<para>
set of logical cpu IDs belonging to the NUMA-node
</para>
</listitem>
</varlistentry>
</variablelist>
<para>
<bridgehead renderas="sect4" id="numa_node_distance_bridgehead">
<phrase id="numa_node_distance"/>
<link linkend="numa_node_distance">Data member
<code>distance</code></link>
</bridgehead>
</para>
<programlisting><phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">vector</phrase><phrase role="special">&lt;</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">uint32_t</phrase> <phrase role="special">&gt;</phrase> <phrase role="identifier">distance</phrase><phrase role="special">;</phrase>
</programlisting>
<variablelist>
<title></title>
<varlistentry>
<term>Effects:</term>
<listitem>
<para>
The distance between NUMA-nodes describe the cots of accessing the remote
memory.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>Note:</term>
<listitem>
<para>
A NUMA-node has a distance of <code><phrase role="number">10</phrase></code>
to itself, remote NUMA-nodes have a distance &gt; <code><phrase role="number">10</phrase></code>.
The index in the array corresponds to the ID <code><phrase role="identifier">id</phrase></code>
of the NUMA-node. At the moment only Linux returns the correct distances,
for all other operating systems remote NUMA-nodes get a default value
of <code><phrase role="number">20</phrase></code>.
</para>
</listitem>
</varlistentry>
</variablelist>
<para>
<bridgehead renderas="sect4" id="numa_node_operator_less_bridgehead">
<phrase id="numa_node_operator_less"/>
<link linkend="numa_node_operator_less">Member
function <code>operator&lt;</code>()</link>
</bridgehead>
</para>
<programlisting><phrase role="keyword">bool</phrase> <phrase role="keyword">operator</phrase><phrase role="special">&lt;(</phrase> <phrase role="identifier">node</phrase> <phrase role="keyword">const</phrase><phrase role="special">&amp;</phrase> <phrase role="identifier">lhs</phrase><phrase role="special">,</phrase> <phrase role="identifier">node</phrase> <phrase role="keyword">const</phrase><phrase role="special">&amp;</phrase> <phrase role="identifier">rhs</phrase><phrase role="special">)</phrase> <phrase role="keyword">const</phrase> <phrase role="keyword">noexcept</phrase><phrase role="special">;</phrase>
</programlisting>
<variablelist>
<title></title>
<varlistentry>
<term>Returns:</term>
<listitem>
<para>
<code><phrase role="keyword">true</phrase></code> if <code><phrase role="identifier">lhs</phrase>
<phrase role="special">!=</phrase> <phrase role="identifier">rhs</phrase></code>
is true and the implementation-defined total order of <code><phrase role="identifier">node</phrase><phrase
role="special">::</phrase><phrase role="identifier">id</phrase></code>
values places <code><phrase role="identifier">lhs</phrase></code> before
<code><phrase role="identifier">rhs</phrase></code>, false otherwise.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>Throws:</term>
<listitem>
<para>
Nothing.
</para>
</listitem>
</varlistentry>
</variablelist>
<para>
<bridgehead renderas="sect4" id="numa_topology_bridgehead">
<phrase id="numa_topology"/>
<link linkend="numa_topology">Non-member function <code>numa::topology()</code></link>
</bridgehead>
</para>
<programlisting><phrase role="preprocessor">#include</phrase> <phrase role="special">&lt;</phrase><phrase role="identifier">boost</phrase><phrase role="special">/</phrase><phrase role="identifier">fiber</phrase><phrase role="special">/</phrase><phrase role="identifier">numa</phrase><phrase role="special">/</phrase><phrase role="identifier">topology</phrase><phrase role="special">.</phrase><phrase role="identifier">hpp</phrase><phrase role="special">&gt;</phrase>
<phrase role="keyword">namespace</phrase> <phrase role="identifier">boost</phrase> <phrase role="special">{</phrase>
<phrase role="keyword">namespace</phrase> <phrase role="identifier">fibers</phrase> <phrase role="special">{</phrase>
<phrase role="keyword">namespace</phrase> <phrase role="identifier">numa</phrase> <phrase role="special">{</phrase>
<phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">vector</phrase><phrase role="special">&lt;</phrase> <phrase role="identifier">node</phrase> <phrase role="special">&gt;</phrase> <phrase role="identifier">topology</phrase><phrase role="special">();</phrase>
<phrase role="special">}}}</phrase>
</programlisting>
<variablelist>
<title></title>
<varlistentry>
<term>Effects:</term>
<listitem>
<para>
Evaluates the NUMA topology.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>Returns:</term>
<listitem>
<para>
a vector of NUMA-nodes describing the NUMA architecture of the system
(each element represents a NUMA-node).
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>Throws:</term>
<listitem>
<para>
<code><phrase role="identifier">system_error</phrase></code>
</para>
</listitem>
</varlistentry>
</variablelist>
<para>
<bridgehead renderas="sect4" id="numa_pin_thread_bridgehead">
<phrase id="numa_pin_thread"/>
<link linkend="numa_pin_thread">Non-member function
<code>numa::pin_thread()</code></link>
</bridgehead>
</para>
<programlisting><phrase role="preprocessor">#include</phrase> <phrase role="special">&lt;</phrase><phrase role="identifier">boost</phrase><phrase role="special">/</phrase><phrase role="identifier">fiber</phrase><phrase role="special">/</phrase><phrase role="identifier">numa</phrase><phrase role="special">/</phrase><phrase role="identifier">pin_thread</phrase><phrase role="special">.</phrase><phrase role="identifier">hpp</phrase><phrase role="special">&gt;</phrase>
<phrase role="keyword">namespace</phrase> <phrase role="identifier">boost</phrase> <phrase role="special">{</phrase>
<phrase role="keyword">namespace</phrase> <phrase role="identifier">fibers</phrase> <phrase role="special">{</phrase>
<phrase role="keyword">namespace</phrase> <phrase role="identifier">numa</phrase> <phrase role="special">{</phrase>
<phrase role="keyword">void</phrase> <phrase role="identifier">pin_thread</phrase><phrase role="special">(</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">uint32_t</phrase> <phrase role="identifier">cpu_id</phrase><phrase role="special">);</phrase>
<phrase role="keyword">void</phrase> <phrase role="identifier">pin_thread</phrase><phrase role="special">(</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">uint32_t</phrase> <phrase role="identifier">cpu_id</phrase><phrase role="special">,</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">thread</phrase><phrase role="special">::</phrase><phrase role="identifier">native_handle_type</phrase> <phrase role="identifier">h</phrase><phrase role="special">);</phrase>
<phrase role="special">}}}</phrase>
</programlisting>
<variablelist>
<title></title>
<varlistentry>
<term>Effects:</term>
<listitem>
<para>
First version pins <code><phrase role="keyword">this</phrase> <phrase
role="identifier">thread</phrase></code> to the logical cpu with ID
<code><phrase role="identifier">cpu_id</phrase></code>, e.g. the operating
system scheduler will not migrate the thread to another logical cpu.
The second variant pins the thread with the native ID <code><phrase role="identifier">h</phrase></code>
to logical cpu with ID <code><phrase role="identifier">cpu_id</phrase></code>.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>Throws:</term>
<listitem>
<para>
<code><phrase role="identifier">system_error</phrase></code>
</para>
</listitem>
</varlistentry>
</variablelist>
<para>
<bridgehead renderas="sect4" id="class_numa_work_stealing_bridgehead">
<phrase id="class_numa_work_stealing"/>
<link linkend="class_numa_work_stealing">Class
<code>numa::work_stealing</code></link>
</bridgehead>
</para>
<para>
This class implements <link linkend="class_algorithm"><code>algorithm</code></link>; the thread running this scheduler
is pinned to the given logical cpu. If the local ready-queue runs out of ready
fibers, ready fibers are stolen from other schedulers that run on logical cpus
that belong to the same NUMA-node (local memory access).<sbr/> If no ready
fibers can be stolen from the local NUMA-node, the algorithm selects schedulers
running on other NUMA-nodes (remote memory access).<sbr/> The victim scheduler
(from which a ready fiber is stolen) is selected at random.
</para>
<programlisting><phrase role="preprocessor">#include</phrase> <phrase role="special">&lt;</phrase><phrase role="identifier">boost</phrase><phrase role="special">/</phrase><phrase role="identifier">fiber</phrase><phrase role="special">/</phrase><phrase role="identifier">numa</phrase><phrase role="special">/</phrase><phrase role="identifier">algo</phrase><phrase role="special">/</phrase><phrase role="identifier">work_stealing</phrase><phrase role="special">.</phrase><phrase role="identifier">hpp</phrase><phrase role="special">&gt;</phrase>
<phrase role="keyword">namespace</phrase> <phrase role="identifier">boost</phrase> <phrase role="special">{</phrase>
<phrase role="keyword">namespace</phrase> <phrase role="identifier">fibers</phrase> <phrase role="special">{</phrase>
<phrase role="keyword">namespace</phrase> <phrase role="identifier">numa</phrase> <phrase role="special">{</phrase>
<phrase role="keyword">namespace</phrase> <phrase role="identifier">algo</phrase> <phrase role="special">{</phrase>
<phrase role="keyword">class</phrase> <phrase role="identifier">work_stealing</phrase> <phrase role="special">:</phrase> <phrase role="keyword">public</phrase> <phrase role="identifier">algorithm</phrase> <phrase role="special">{</phrase>
<phrase role="keyword">public</phrase><phrase role="special">:</phrase>
<phrase role="identifier">work_stealing</phrase><phrase role="special">(</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">uint32_t</phrase> <phrase role="identifier">cpu_id</phrase><phrase role="special">,</phrase>
<phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">uint32_t</phrase> <phrase role="identifier">node_id</phrase><phrase role="special">,</phrase>
<phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">vector</phrase><phrase role="special">&lt;</phrase> <phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">fibers</phrase><phrase role="special">::</phrase><phrase role="identifier">numa</phrase><phrase role="special">::</phrase><phrase role="identifier">node</phrase> <phrase role="special">&gt;</phrase> <phrase role="keyword">const</phrase><phrase role="special">&amp;</phrase> <phrase role="identifier">topo</phrase><phrase role="special">,</phrase>
<phrase role="keyword">bool</phrase> <phrase role="identifier">suspend</phrase> <phrase role="special">=</phrase> <phrase role="keyword">false</phrase><phrase role="special">);</phrase>
<phrase role="identifier">work_stealing</phrase><phrase role="special">(</phrase> <phrase role="identifier">work_stealing</phrase> <phrase role="keyword">const</phrase><phrase role="special">&amp;)</phrase> <phrase role="special">=</phrase> <phrase role="keyword">delete</phrase><phrase role="special">;</phrase>
<phrase role="identifier">work_stealing</phrase><phrase role="special">(</phrase> <phrase role="identifier">work_stealing</phrase> <phrase role="special">&amp;&amp;)</phrase> <phrase role="special">=</phrase> <phrase role="keyword">delete</phrase><phrase role="special">;</phrase>
<phrase role="identifier">work_stealing</phrase> <phrase role="special">&amp;</phrase> <phrase role="keyword">operator</phrase><phrase role="special">=(</phrase> <phrase role="identifier">work_stealing</phrase> <phrase role="keyword">const</phrase><phrase role="special">&amp;)</phrase> <phrase role="special">=</phrase> <phrase role="keyword">delete</phrase><phrase role="special">;</phrase>
<phrase role="identifier">work_stealing</phrase> <phrase role="special">&amp;</phrase> <phrase role="keyword">operator</phrase><phrase role="special">=(</phrase> <phrase role="identifier">work_stealing</phrase> <phrase role="special">&amp;&amp;)</phrase> <phrase role="special">=</phrase> <phrase role="keyword">delete</phrase><phrase role="special">;</phrase>
<phrase role="keyword">virtual</phrase> <phrase role="keyword">void</phrase> <phrase role="identifier">awakened</phrase><phrase role="special">(</phrase> <phrase role="identifier">context</phrase> <phrase role="special">*)</phrase> <phrase role="keyword">noexcept</phrase><phrase role="special">;</phrase>
<phrase role="keyword">virtual</phrase> <phrase role="identifier">context</phrase> <phrase role="special">*</phrase> <phrase role="identifier">pick_next</phrase><phrase role="special">()</phrase> <phrase role="keyword">noexcept</phrase><phrase role="special">;</phrase>
<phrase role="keyword">virtual</phrase> <phrase role="keyword">bool</phrase> <phrase role="identifier">has_ready_fibers</phrase><phrase role="special">()</phrase> <phrase role="keyword">const</phrase> <phrase role="keyword">noexcept</phrase><phrase role="special">;</phrase>
<phrase role="keyword">virtual</phrase> <phrase role="keyword">void</phrase> <phrase role="identifier">suspend_until</phrase><phrase role="special">(</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">chrono</phrase><phrase role="special">::</phrase><phrase role="identifier">steady_clock</phrase><phrase role="special">::</phrase><phrase role="identifier">time_point</phrase> <phrase role="keyword">const</phrase><phrase role="special">&amp;)</phrase> <phrase role="keyword">noexcept</phrase><phrase role="special">;</phrase>
<phrase role="keyword">virtual</phrase> <phrase role="keyword">void</phrase> <phrase role="identifier">notify</phrase><phrase role="special">()</phrase> <phrase role="keyword">noexcept</phrase><phrase role="special">;</phrase>
<phrase role="special">};</phrase>
<phrase role="special">}}}}</phrase>
</programlisting>
<bridgehead renderas="sect3" id="fiber.numa.h2">
<phrase id="fiber.numa.constructor"/><link linkend="fiber.numa.constructor">Constructor</link>
</bridgehead>
<programlisting><phrase role="identifier">work_stealing</phrase><phrase role="special">(</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">uint32_t</phrase> <phrase role="identifier">cpu_id</phrase><phrase role="special">,</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">uint32_t</phrase> <phrase role="identifier">node_id</phrase><phrase role="special">,</phrase>
<phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">vector</phrase><phrase role="special">&lt;</phrase> <phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">fibers</phrase><phrase role="special">::</phrase><phrase role="identifier">numa</phrase><phrase role="special">::</phrase><phrase role="identifier">node</phrase> <phrase role="special">&gt;</phrase> <phrase role="keyword">const</phrase><phrase role="special">&amp;</phrase> <phrase role="identifier">topo</phrase><phrase role="special">,</phrase>
<phrase role="keyword">bool</phrase> <phrase role="identifier">suspend</phrase> <phrase role="special">=</phrase> <phrase role="keyword">false</phrase><phrase role="special">);</phrase>
</programlisting>
<variablelist>
<title></title>
<varlistentry>
<term>Effects:</term>
<listitem>
<para>
Constructs work-stealing scheduling algorithm. The thread is pinned to
logical cpu with ID <code><phrase role="identifier">cpu_id</phrase></code>.
If local ready-queue runs out of ready fibers, ready fibers are stolen
from other schedulers using <code><phrase role="identifier">topology</phrase></code>
(represents the NUMA-topology of the system).
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>Throws:</term>
<listitem>
<para>
<code><phrase role="identifier">system_error</phrase></code>
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>Note:</term>
<listitem>
<para>
If <code><phrase role="identifier">suspend</phrase></code> is set to
<code><phrase role="keyword">true</phrase></code>, then the scheduler
suspends if no ready fiber could be stolen. The scheduler will by woken
up if a sleeping fiber times out or it was notified from remote (other
thread or fiber scheduler).
</para>
</listitem>
</varlistentry>
</variablelist>
<para>
<bridgehead renderas="sect4" id="numa_work_stealing_awakened_bridgehead">
<phrase id="numa_work_stealing_awakened"/>
<link linkend="numa_work_stealing_awakened">Member
function <code>awakened</code>()</link>
</bridgehead>
</para>
<programlisting><phrase role="keyword">virtual</phrase> <phrase role="keyword">void</phrase> <phrase role="identifier">awakened</phrase><phrase role="special">(</phrase> <phrase role="identifier">context</phrase> <phrase role="special">*</phrase> <phrase role="identifier">f</phrase><phrase role="special">)</phrase> <phrase role="keyword">noexcept</phrase><phrase role="special">;</phrase>
</programlisting>
<variablelist>
<title></title>
<varlistentry>
<term>Effects:</term>
<listitem>
<para>
Enqueues fiber <code><phrase role="identifier">f</phrase></code> onto
the shared ready queue.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>Throws:</term>
<listitem>
<para>
Nothing.
</para>
</listitem>
</varlistentry>
</variablelist>
<para>
<bridgehead renderas="sect4" id="numa_work_stealing_pick_next_bridgehead">
<phrase id="numa_work_stealing_pick_next"/>
<link linkend="numa_work_stealing_pick_next">Member
function <code>pick_next</code>()</link>
</bridgehead>
</para>
<programlisting><phrase role="keyword">virtual</phrase> <phrase role="identifier">context</phrase> <phrase role="special">*</phrase> <phrase role="identifier">pick_next</phrase><phrase role="special">()</phrase> <phrase role="keyword">noexcept</phrase><phrase role="special">;</phrase>
</programlisting>
<variablelist>
<title></title>
<varlistentry>
<term>Returns:</term>
<listitem>
<para>
the fiber at the head of the ready queue, or <code><phrase role="keyword">nullptr</phrase></code>
if the queue is empty.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>Throws:</term>
<listitem>
<para>
Nothing.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>Note:</term>
<listitem>
<para>
Placing ready fibers onto the tail of the sahred queue, and returning
them from the head of that queue, shares the thread between ready fibers
in round-robin fashion.
</para>
</listitem>
</varlistentry>
</variablelist>
<para>
<bridgehead renderas="sect4" id="numa_work_stealing_has_ready_fibers_bridgehead">
<phrase id="numa_work_stealing_has_ready_fibers"/>
<link linkend="numa_work_stealing_has_ready_fibers">Member
function <code>has_ready_fibers</code>()</link>
</bridgehead>
</para>
<programlisting><phrase role="keyword">virtual</phrase> <phrase role="keyword">bool</phrase> <phrase role="identifier">has_ready_fibers</phrase><phrase role="special">()</phrase> <phrase role="keyword">const</phrase> <phrase role="keyword">noexcept</phrase><phrase role="special">;</phrase>
</programlisting>
<variablelist>
<title></title>
<varlistentry>
<term>Returns:</term>
<listitem>
<para>
<code><phrase role="keyword">true</phrase></code> if scheduler has fibers
ready to run.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>Throws:</term>
<listitem>
<para>
Nothing.
</para>
</listitem>
</varlistentry>
</variablelist>
<para>
<bridgehead renderas="sect4" id="numa_work_stealing_suspend_until_bridgehead">
<phrase id="numa_work_stealing_suspend_until"/>
<link linkend="numa_work_stealing_suspend_until">Member
function <code>suspend_until</code>()</link>
</bridgehead>
</para>
<programlisting><phrase role="keyword">virtual</phrase> <phrase role="keyword">void</phrase> <phrase role="identifier">suspend_until</phrase><phrase role="special">(</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">chrono</phrase><phrase role="special">::</phrase><phrase role="identifier">steady_clock</phrase><phrase role="special">::</phrase><phrase role="identifier">time_point</phrase> <phrase role="keyword">const</phrase><phrase role="special">&amp;</phrase> <phrase role="identifier">abs_time</phrase><phrase role="special">)</phrase> <phrase role="keyword">noexcept</phrase><phrase role="special">;</phrase>
</programlisting>
<variablelist>
<title></title>
<varlistentry>
<term>Effects:</term>
<listitem>
<para>
Informs <code><phrase role="identifier">work_stealing</phrase></code>
that no ready fiber will be available until time-point <code><phrase
role="identifier">abs_time</phrase></code>. This implementation blocks
in <ulink url="http://en.cppreference.com/w/cpp/thread/condition_variable/wait_until"><code><phrase
role="identifier">std</phrase><phrase role="special">::</phrase><phrase
role="identifier">condition_variable</phrase><phrase role="special">::</phrase><phrase
role="identifier">wait_until</phrase><phrase role="special">()</phrase></code></ulink>.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>Throws:</term>
<listitem>
<para>
Nothing.
</para>
</listitem>
</varlistentry>
</variablelist>
<para>
<bridgehead renderas="sect4" id="numa_work_stealing_notify_bridgehead">
<phrase id="numa_work_stealing_notify"/>
<link linkend="numa_work_stealing_notify">Member
function <code>notify</code>()</link>
</bridgehead>
</para>
<programlisting><phrase role="keyword">virtual</phrase> <phrase role="keyword">void</phrase> <phrase role="identifier">notify</phrase><phrase role="special">()</phrase> <phrase role="keyword">noexcept</phrase> <phrase role="special">=</phrase> <phrase role="number">0</phrase><phrase role="special">;</phrase>
</programlisting>
<variablelist>
<title></title>
<varlistentry>
<term>Effects:</term>
<listitem>
<para>
Wake up a pending call to <link linkend="work_stealing_suspend_until"><code>work_stealing::suspend_until()</code></link>,
some fibers might be ready. This implementation wakes <code><phrase role="identifier">suspend_until</phrase><phrase
role="special">()</phrase></code> via <ulink url="http://en.cppreference.com/w/cpp/thread/condition_variable/notify_all"><code><phrase
role="identifier">std</phrase><phrase role="special">::</phrase><phrase
role="identifier">condition_variable</phrase><phrase role="special">::</phrase><phrase
role="identifier">notify_all</phrase><phrase role="special">()</phrase></code></ulink>.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>Throws:</term>
<listitem>
<para>
Nothing.
</para>
</listitem>
</varlistentry>
</variablelist>
</section>
<section id="fiber.gpu_computing">
<title><link linkend="fiber.gpu_computing">GPU computing</link></title>
<section id="fiber.gpu_computing.cuda">
<title><anchor id="cuda"/><link linkend="fiber.gpu_computing.cuda">CUDA</link></title>
<para>
<ulink url="http://developer.nvidia.com/cuda-zone/">CUDA (Compute Unified
Device Architecture)</ulink> is a platform for parallel computing on NVIDIA
GPUs. The application programming interface of CUDA gives access to GPU's
instruction set and computation resources (Execution of compute kernels).
</para>
<bridgehead renderas="sect4" id="fiber.gpu_computing.cuda.h0">
<phrase id="fiber.gpu_computing.cuda.synchronization_with_cuda_streams"/><link
linkend="fiber.gpu_computing.cuda.synchronization_with_cuda_streams">Synchronization
with CUDA streams</link>
</bridgehead>
<para>
CUDA operation such as compute kernels or memory transfer (between host and
device) can be grouped/queued by CUDA streams. are executed on the GPUs.
Boost.Fiber enables a fiber to sleep (suspend) till a CUDA stream has completed
its operations. This enables applications to run other fibers on the CPU
without the need to spawn an additional OS-threads. And resume the fiber
when the CUDA streams has finished.
</para>
<programlisting><phrase role="identifier">__global__</phrase>
<phrase role="keyword">void</phrase> <phrase role="identifier">kernel</phrase><phrase role="special">(</phrase> <phrase role="keyword">int</phrase> <phrase role="identifier">size</phrase><phrase role="special">,</phrase> <phrase role="keyword">int</phrase> <phrase role="special">*</phrase> <phrase role="identifier">a</phrase><phrase role="special">,</phrase> <phrase role="keyword">int</phrase> <phrase role="special">*</phrase> <phrase role="identifier">b</phrase><phrase role="special">,</phrase> <phrase role="keyword">int</phrase> <phrase role="special">*</phrase> <phrase role="identifier">c</phrase><phrase role="special">)</phrase> <phrase role="special">{</phrase>
<phrase role="keyword">int</phrase> <phrase role="identifier">idx</phrase> <phrase role="special">=</phrase> <phrase role="identifier">threadIdx</phrase><phrase role="special">.</phrase><phrase role="identifier">x</phrase> <phrase role="special">+</phrase> <phrase role="identifier">blockIdx</phrase><phrase role="special">.</phrase><phrase role="identifier">x</phrase> <phrase role="special">*</phrase> <phrase role="identifier">blockDim</phrase><phrase role="special">.</phrase><phrase role="identifier">x</phrase><phrase role="special">;</phrase>
<phrase role="keyword">if</phrase> <phrase role="special">(</phrase> <phrase role="identifier">idx</phrase> <phrase role="special">&lt;</phrase> <phrase role="identifier">size</phrase><phrase role="special">)</phrase> <phrase role="special">{</phrase>
<phrase role="keyword">int</phrase> <phrase role="identifier">idx1</phrase> <phrase role="special">=</phrase> <phrase role="special">(</phrase><phrase role="identifier">idx</phrase> <phrase role="special">+</phrase> <phrase role="number">1</phrase><phrase role="special">)</phrase> <phrase role="special">%</phrase> <phrase role="number">256</phrase><phrase role="special">;</phrase>
<phrase role="keyword">int</phrase> <phrase role="identifier">idx2</phrase> <phrase role="special">=</phrase> <phrase role="special">(</phrase><phrase role="identifier">idx</phrase> <phrase role="special">+</phrase> <phrase role="number">2</phrase><phrase role="special">)</phrase> <phrase role="special">%</phrase> <phrase role="number">256</phrase><phrase role="special">;</phrase>
<phrase role="keyword">float</phrase> <phrase role="identifier">as</phrase> <phrase role="special">=</phrase> <phrase role="special">(</phrase><phrase role="identifier">a</phrase><phrase role="special">[</phrase><phrase role="identifier">idx</phrase><phrase role="special">]</phrase> <phrase role="special">+</phrase> <phrase role="identifier">a</phrase><phrase role="special">[</phrase><phrase role="identifier">idx1</phrase><phrase role="special">]</phrase> <phrase role="special">+</phrase> <phrase role="identifier">a</phrase><phrase role="special">[</phrase><phrase role="identifier">idx2</phrase><phrase role="special">])</phrase> <phrase role="special">/</phrase> <phrase role="number">3.0f</phrase><phrase role="special">;</phrase>
<phrase role="keyword">float</phrase> <phrase role="identifier">bs</phrase> <phrase role="special">=</phrase> <phrase role="special">(</phrase><phrase role="identifier">b</phrase><phrase role="special">[</phrase><phrase role="identifier">idx</phrase><phrase role="special">]</phrase> <phrase role="special">+</phrase> <phrase role="identifier">b</phrase><phrase role="special">[</phrase><phrase role="identifier">idx1</phrase><phrase role="special">]</phrase> <phrase role="special">+</phrase> <phrase role="identifier">b</phrase><phrase role="special">[</phrase><phrase role="identifier">idx2</phrase><phrase role="special">])</phrase> <phrase role="special">/</phrase> <phrase role="number">3.0f</phrase><phrase role="special">;</phrase>
<phrase role="identifier">c</phrase><phrase role="special">[</phrase><phrase role="identifier">idx</phrase><phrase role="special">]</phrase> <phrase role="special">=</phrase> <phrase role="special">(</phrase><phrase role="identifier">as</phrase> <phrase role="special">+</phrase> <phrase role="identifier">bs</phrase><phrase role="special">)</phrase> <phrase role="special">/</phrase> <phrase role="number">2</phrase><phrase role="special">;</phrase>
<phrase role="special">}</phrase>
<phrase role="special">}</phrase>
<phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">fibers</phrase><phrase role="special">::</phrase><phrase role="identifier">fiber</phrase> <phrase role="identifier">f</phrase><phrase role="special">([&amp;</phrase><phrase role="identifier">done</phrase><phrase role="special">]{</phrase>
<phrase role="identifier">cudaStream_t</phrase> <phrase role="identifier">stream</phrase><phrase role="special">;</phrase>
<phrase role="identifier">cudaStreamCreate</phrase><phrase role="special">(</phrase> <phrase role="special">&amp;</phrase> <phrase role="identifier">stream</phrase><phrase role="special">);</phrase>
<phrase role="keyword">int</phrase> <phrase role="identifier">size</phrase> <phrase role="special">=</phrase> <phrase role="number">1024</phrase> <phrase role="special">*</phrase> <phrase role="number">1024</phrase><phrase role="special">;</phrase>
<phrase role="keyword">int</phrase> <phrase role="identifier">full_size</phrase> <phrase role="special">=</phrase> <phrase role="number">20</phrase> <phrase role="special">*</phrase> <phrase role="identifier">size</phrase><phrase role="special">;</phrase>
<phrase role="keyword">int</phrase> <phrase role="special">*</phrase> <phrase role="identifier">host_a</phrase><phrase role="special">,</phrase> <phrase role="special">*</phrase> <phrase role="identifier">host_b</phrase><phrase role="special">,</phrase> <phrase role="special">*</phrase> <phrase role="identifier">host_c</phrase><phrase role="special">;</phrase>
<phrase role="identifier">cudaHostAlloc</phrase><phrase role="special">(</phrase> <phrase role="special">&amp;</phrase> <phrase role="identifier">host_a</phrase><phrase role="special">,</phrase> <phrase role="identifier">full_size</phrase> <phrase role="special">*</phrase> <phrase role="keyword">sizeof</phrase><phrase role="special">(</phrase> <phrase role="keyword">int</phrase><phrase role="special">),</phrase> <phrase role="identifier">cudaHostAllocDefault</phrase><phrase role="special">);</phrase>
<phrase role="identifier">cudaHostAlloc</phrase><phrase role="special">(</phrase> <phrase role="special">&amp;</phrase> <phrase role="identifier">host_b</phrase><phrase role="special">,</phrase> <phrase role="identifier">full_size</phrase> <phrase role="special">*</phrase> <phrase role="keyword">sizeof</phrase><phrase role="special">(</phrase> <phrase role="keyword">int</phrase><phrase role="special">),</phrase> <phrase role="identifier">cudaHostAllocDefault</phrase><phrase role="special">);</phrase>
<phrase role="identifier">cudaHostAlloc</phrase><phrase role="special">(</phrase> <phrase role="special">&amp;</phrase> <phrase role="identifier">host_c</phrase><phrase role="special">,</phrase> <phrase role="identifier">full_size</phrase> <phrase role="special">*</phrase> <phrase role="keyword">sizeof</phrase><phrase role="special">(</phrase> <phrase role="keyword">int</phrase><phrase role="special">),</phrase> <phrase role="identifier">cudaHostAllocDefault</phrase><phrase role="special">);</phrase>
<phrase role="keyword">int</phrase> <phrase role="special">*</phrase> <phrase role="identifier">dev_a</phrase><phrase role="special">,</phrase> <phrase role="special">*</phrase> <phrase role="identifier">dev_b</phrase><phrase role="special">,</phrase> <phrase role="special">*</phrase> <phrase role="identifier">dev_c</phrase><phrase role="special">;</phrase>
<phrase role="identifier">cudaMalloc</phrase><phrase role="special">(</phrase> <phrase role="special">&amp;</phrase> <phrase role="identifier">dev_a</phrase><phrase role="special">,</phrase> <phrase role="identifier">size</phrase> <phrase role="special">*</phrase> <phrase role="keyword">sizeof</phrase><phrase role="special">(</phrase> <phrase role="keyword">int</phrase><phrase role="special">)</phrase> <phrase role="special">);</phrase>
<phrase role="identifier">cudaMalloc</phrase><phrase role="special">(</phrase> <phrase role="special">&amp;</phrase> <phrase role="identifier">dev_b</phrase><phrase role="special">,</phrase> <phrase role="identifier">size</phrase> <phrase role="special">*</phrase> <phrase role="keyword">sizeof</phrase><phrase role="special">(</phrase> <phrase role="keyword">int</phrase><phrase role="special">)</phrase> <phrase role="special">);</phrase>
<phrase role="identifier">cudaMalloc</phrase><phrase role="special">(</phrase> <phrase role="special">&amp;</phrase> <phrase role="identifier">dev_c</phrase><phrase role="special">,</phrase> <phrase role="identifier">size</phrase> <phrase role="special">*</phrase> <phrase role="keyword">sizeof</phrase><phrase role="special">(</phrase> <phrase role="keyword">int</phrase><phrase role="special">)</phrase> <phrase role="special">);</phrase>
<phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">minstd_rand</phrase> <phrase role="identifier">generator</phrase><phrase role="special">;</phrase>
<phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">uniform_int_distribution</phrase><phrase role="special">&lt;&gt;</phrase> <phrase role="identifier">distribution</phrase><phrase role="special">(</phrase><phrase role="number">1</phrase><phrase role="special">,</phrase> <phrase role="number">6</phrase><phrase role="special">);</phrase>
<phrase role="keyword">for</phrase> <phrase role="special">(</phrase> <phrase role="keyword">int</phrase> <phrase role="identifier">i</phrase> <phrase role="special">=</phrase> <phrase role="number">0</phrase><phrase role="special">;</phrase> <phrase role="identifier">i</phrase> <phrase role="special">&lt;</phrase> <phrase role="identifier">full_size</phrase><phrase role="special">;</phrase> <phrase role="special">++</phrase><phrase role="identifier">i</phrase><phrase role="special">)</phrase> <phrase role="special">{</phrase>
<phrase role="identifier">host_a</phrase><phrase role="special">[</phrase><phrase role="identifier">i</phrase><phrase role="special">]</phrase> <phrase role="special">=</phrase> <phrase role="identifier">distribution</phrase><phrase role="special">(</phrase> <phrase role="identifier">generator</phrase><phrase role="special">);</phrase>
<phrase role="identifier">host_b</phrase><phrase role="special">[</phrase><phrase role="identifier">i</phrase><phrase role="special">]</phrase> <phrase role="special">=</phrase> <phrase role="identifier">distribution</phrase><phrase role="special">(</phrase> <phrase role="identifier">generator</phrase><phrase role="special">);</phrase>
<phrase role="special">}</phrase>
<phrase role="keyword">for</phrase> <phrase role="special">(</phrase> <phrase role="keyword">int</phrase> <phrase role="identifier">i</phrase> <phrase role="special">=</phrase> <phrase role="number">0</phrase><phrase role="special">;</phrase> <phrase role="identifier">i</phrase> <phrase role="special">&lt;</phrase> <phrase role="identifier">full_size</phrase><phrase role="special">;</phrase> <phrase role="identifier">i</phrase> <phrase role="special">+=</phrase> <phrase role="identifier">size</phrase><phrase role="special">)</phrase> <phrase role="special">{</phrase>
<phrase role="identifier">cudaMemcpyAsync</phrase><phrase role="special">(</phrase> <phrase role="identifier">dev_a</phrase><phrase role="special">,</phrase> <phrase role="identifier">host_a</phrase> <phrase role="special">+</phrase> <phrase role="identifier">i</phrase><phrase role="special">,</phrase> <phrase role="identifier">size</phrase> <phrase role="special">*</phrase> <phrase role="keyword">sizeof</phrase><phrase role="special">(</phrase> <phrase role="keyword">int</phrase><phrase role="special">),</phrase> <phrase role="identifier">cudaMemcpyHostToDevice</phrase><phrase role="special">,</phrase> <phrase role="identifier">stream</phrase><phrase role="special">);</phrase>
<phrase role="identifier">cudaMemcpyAsync</phrase><phrase role="special">(</phrase> <phrase role="identifier">dev_b</phrase><phrase role="special">,</phrase> <phrase role="identifier">host_b</phrase> <phrase role="special">+</phrase> <phrase role="identifier">i</phrase><phrase role="special">,</phrase> <phrase role="identifier">size</phrase> <phrase role="special">*</phrase> <phrase role="keyword">sizeof</phrase><phrase role="special">(</phrase> <phrase role="keyword">int</phrase><phrase role="special">),</phrase> <phrase role="identifier">cudaMemcpyHostToDevice</phrase><phrase role="special">,</phrase> <phrase role="identifier">stream</phrase><phrase role="special">);</phrase>
<phrase role="identifier">kernel</phrase><phrase role="special">&lt;&lt;&lt;</phrase> <phrase role="identifier">size</phrase> <phrase role="special">/</phrase> <phrase role="number">256</phrase><phrase role="special">,</phrase> <phrase role="number">256</phrase><phrase role="special">,</phrase> <phrase role="number">0</phrase><phrase role="special">,</phrase> <phrase role="identifier">stream</phrase> <phrase role="special">&gt;&gt;&gt;(</phrase> <phrase role="identifier">size</phrase><phrase role="special">,</phrase> <phrase role="identifier">dev_a</phrase><phrase role="special">,</phrase> <phrase role="identifier">dev_b</phrase><phrase role="special">,</phrase> <phrase role="identifier">dev_c</phrase><phrase role="special">);</phrase>
<phrase role="identifier">cudaMemcpyAsync</phrase><phrase role="special">(</phrase> <phrase role="identifier">host_c</phrase> <phrase role="special">+</phrase> <phrase role="identifier">i</phrase><phrase role="special">,</phrase> <phrase role="identifier">dev_c</phrase><phrase role="special">,</phrase> <phrase role="identifier">size</phrase> <phrase role="special">*</phrase> <phrase role="keyword">sizeof</phrase><phrase role="special">(</phrase> <phrase role="keyword">int</phrase><phrase role="special">),</phrase> <phrase role="identifier">cudaMemcpyDeviceToHost</phrase><phrase role="special">,</phrase> <phrase role="identifier">stream</phrase><phrase role="special">);</phrase>
<phrase role="special">}</phrase>
<phrase role="keyword">auto</phrase> <phrase role="identifier">result</phrase> <phrase role="special">=</phrase> <phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">fibers</phrase><phrase role="special">::</phrase><phrase role="identifier">cuda</phrase><phrase role="special">::</phrase><phrase role="identifier">waitfor_all</phrase><phrase role="special">(</phrase> <phrase role="identifier">stream</phrase><phrase role="special">);</phrase> <phrase role="comment">// suspend fiber till CUDA stream has finished</phrase>
<phrase role="identifier">BOOST_ASSERT</phrase><phrase role="special">(</phrase> <phrase role="identifier">stream</phrase> <phrase role="special">==</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">get</phrase><phrase role="special">&lt;</phrase> <phrase role="number">0</phrase> <phrase role="special">&gt;(</phrase> <phrase role="identifier">result</phrase><phrase role="special">)</phrase> <phrase role="special">);</phrase>
<phrase role="identifier">BOOST_ASSERT</phrase><phrase role="special">(</phrase> <phrase role="identifier">cudaSuccess</phrase> <phrase role="special">==</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">get</phrase><phrase role="special">&lt;</phrase> <phrase role="number">1</phrase> <phrase role="special">&gt;(</phrase> <phrase role="identifier">result</phrase><phrase role="special">)</phrase> <phrase role="special">);</phrase>
<phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">cout</phrase> <phrase role="special">&lt;&lt;</phrase> <phrase role="string">&quot;f1: GPU computation finished&quot;</phrase> <phrase role="special">&lt;&lt;</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">endl</phrase><phrase role="special">;</phrase>
<phrase role="identifier">cudaFreeHost</phrase><phrase role="special">(</phrase> <phrase role="identifier">host_a</phrase><phrase role="special">);</phrase>
<phrase role="identifier">cudaFreeHost</phrase><phrase role="special">(</phrase> <phrase role="identifier">host_b</phrase><phrase role="special">);</phrase>
<phrase role="identifier">cudaFreeHost</phrase><phrase role="special">(</phrase> <phrase role="identifier">host_c</phrase><phrase role="special">);</phrase>
<phrase role="identifier">cudaFree</phrase><phrase role="special">(</phrase> <phrase role="identifier">dev_a</phrase><phrase role="special">);</phrase>
<phrase role="identifier">cudaFree</phrase><phrase role="special">(</phrase> <phrase role="identifier">dev_b</phrase><phrase role="special">);</phrase>
<phrase role="identifier">cudaFree</phrase><phrase role="special">(</phrase> <phrase role="identifier">dev_c</phrase><phrase role="special">);</phrase>
<phrase role="identifier">cudaStreamDestroy</phrase><phrase role="special">(</phrase> <phrase role="identifier">stream</phrase><phrase role="special">);</phrase>
<phrase role="special">});</phrase>
<phrase role="identifier">f</phrase><phrase role="special">.</phrase><phrase role="identifier">join</phrase><phrase role="special">();</phrase>
</programlisting>
<bridgehead renderas="sect4" id="fiber.gpu_computing.cuda.h1">
<phrase id="fiber.gpu_computing.cuda.synopsis"/><link linkend="fiber.gpu_computing.cuda.synopsis">Synopsis</link>
</bridgehead>
<programlisting><phrase role="preprocessor">#include</phrase> <phrase role="special">&lt;</phrase><phrase role="identifier">boost</phrase><phrase role="special">/</phrase><phrase role="identifier">fiber</phrase><phrase role="special">/</phrase><phrase role="identifier">cuda</phrase><phrase role="special">/</phrase><phrase role="identifier">waitfor</phrase><phrase role="special">.</phrase><phrase role="identifier">hpp</phrase><phrase role="special">&gt;</phrase>
<phrase role="keyword">namespace</phrase> <phrase role="identifier">boost</phrase> <phrase role="special">{</phrase>
<phrase role="keyword">namespace</phrase> <phrase role="identifier">fibers</phrase> <phrase role="special">{</phrase>
<phrase role="keyword">namespace</phrase> <phrase role="identifier">cuda</phrase> <phrase role="special">{</phrase>
<phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">tuple</phrase><phrase role="special">&lt;</phrase> <phrase role="identifier">cudaStream_t</phrase><phrase role="special">,</phrase> <phrase role="identifier">cudaError_t</phrase> <phrase role="special">&gt;</phrase> <phrase role="identifier">waitfor_all</phrase><phrase role="special">(</phrase> <phrase role="identifier">cudaStream_t</phrase> <phrase role="identifier">st</phrase><phrase role="special">);</phrase>
<phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">vector</phrase><phrase role="special">&lt;</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">tuple</phrase><phrase role="special">&lt;</phrase> <phrase role="identifier">cudaStream_t</phrase><phrase role="special">,</phrase> <phrase role="identifier">cudaError_t</phrase> <phrase role="special">&gt;</phrase> <phrase role="special">&gt;</phrase> <phrase role="identifier">waitfor_all</phrase><phrase role="special">(</phrase> <phrase role="identifier">cudaStream_t</phrase> <phrase role="special">...</phrase> <phrase role="identifier">st</phrase><phrase role="special">);</phrase>
<phrase role="special">}}}</phrase>
</programlisting>
<para>
<bridgehead renderas="sect4" id="cuda_waitfor_bridgehead">
<phrase id="cuda_waitfor"/>
<link linkend="cuda_waitfor">Non-member function <code>cuda::waitfor()</code></link>
</bridgehead>
</para>
<programlisting><phrase role="preprocessor">#include</phrase> <phrase role="special">&lt;</phrase><phrase role="identifier">boost</phrase><phrase role="special">/</phrase><phrase role="identifier">fiber</phrase><phrase role="special">/</phrase><phrase role="identifier">cuda</phrase><phrase role="special">/</phrase><phrase role="identifier">waitfor</phrase><phrase role="special">.</phrase><phrase role="identifier">hpp</phrase><phrase role="special">&gt;</phrase>
<phrase role="keyword">namespace</phrase> <phrase role="identifier">boost</phrase> <phrase role="special">{</phrase>
<phrase role="keyword">namespace</phrase> <phrase role="identifier">fibers</phrase> <phrase role="special">{</phrase>
<phrase role="keyword">namespace</phrase> <phrase role="identifier">cuda</phrase> <phrase role="special">{</phrase>
<phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">tuple</phrase><phrase role="special">&lt;</phrase> <phrase role="identifier">cudaStream_t</phrase><phrase role="special">,</phrase> <phrase role="identifier">cudaError_t</phrase> <phrase role="special">&gt;</phrase> <phrase role="identifier">waitfor_all</phrase><phrase role="special">(</phrase> <phrase role="identifier">cudaStream_t</phrase> <phrase role="identifier">st</phrase><phrase role="special">);</phrase>
<phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">vector</phrase><phrase role="special">&lt;</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">tuple</phrase><phrase role="special">&lt;</phrase> <phrase role="identifier">cudaStream_t</phrase><phrase role="special">,</phrase> <phrase role="identifier">cudaError_t</phrase> <phrase role="special">&gt;</phrase> <phrase role="special">&gt;</phrase> <phrase role="identifier">waitfor_all</phrase><phrase role="special">(</phrase> <phrase role="identifier">cudaStream_t</phrase> <phrase role="special">...</phrase> <phrase role="identifier">st</phrase><phrase role="special">);</phrase>
<phrase role="special">}}}</phrase>
</programlisting>
<variablelist>
<title></title>
<varlistentry>
<term>Effects:</term>
<listitem>
<para>
Suspends active fiber till CUDA stream has finished its operations.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>Returns:</term>
<listitem>
<para>
tuple of stream reference and the CUDA stream status
</para>
</listitem>
</varlistentry>
</variablelist>
</section>
<section id="fiber.gpu_computing.hip">
<title><anchor id="hip"/><link linkend="fiber.gpu_computing.hip">ROCm/HIP</link></title>
<para>
<ulink url="http://github.com/ROCm-Developer-Tools/HIP/tree/roc-1.6.0/">HIP</ulink>
is part of the <ulink url="http://rocm.github.io/">ROC (Radeon Open Compute)</ulink>
platform for parallel computing on AMD and NVIDIA GPUs. The application programming
interface of HIP gives access to GPU's instruction set and computation resources
(Execution of compute kernels).
</para>
<bridgehead renderas="sect4" id="fiber.gpu_computing.hip.h0">
<phrase id="fiber.gpu_computing.hip.synchronization_with_rocm_hip_streams"/><link
linkend="fiber.gpu_computing.hip.synchronization_with_rocm_hip_streams">Synchronization
with ROCm/HIP streams</link>
</bridgehead>
<para>
HIP operation such as compute kernels or memory transfer (between host and
device) can be grouped/queued by HIP streams. are executed on the GPUs. Boost.Fiber
enables a fiber to sleep (suspend) till a HIP stream has completed its operations.
This enables applications to run other fibers on the CPU without the need
to spawn an additional OS-threads. And resume the fiber when the HIP streams
has finished.
</para>
<programlisting><phrase role="identifier">__global__</phrase>
<phrase role="keyword">void</phrase> <phrase role="identifier">kernel</phrase><phrase role="special">(</phrase> <phrase role="keyword">int</phrase> <phrase role="identifier">size</phrase><phrase role="special">,</phrase> <phrase role="keyword">int</phrase> <phrase role="special">*</phrase> <phrase role="identifier">a</phrase><phrase role="special">,</phrase> <phrase role="keyword">int</phrase> <phrase role="special">*</phrase> <phrase role="identifier">b</phrase><phrase role="special">,</phrase> <phrase role="keyword">int</phrase> <phrase role="special">*</phrase> <phrase role="identifier">c</phrase><phrase role="special">)</phrase> <phrase role="special">{</phrase>
<phrase role="keyword">int</phrase> <phrase role="identifier">idx</phrase> <phrase role="special">=</phrase> <phrase role="identifier">threadIdx</phrase><phrase role="special">.</phrase><phrase role="identifier">x</phrase> <phrase role="special">+</phrase> <phrase role="identifier">blockIdx</phrase><phrase role="special">.</phrase><phrase role="identifier">x</phrase> <phrase role="special">*</phrase> <phrase role="identifier">blockDim</phrase><phrase role="special">.</phrase><phrase role="identifier">x</phrase><phrase role="special">;</phrase>
<phrase role="keyword">if</phrase> <phrase role="special">(</phrase> <phrase role="identifier">idx</phrase> <phrase role="special">&lt;</phrase> <phrase role="identifier">size</phrase><phrase role="special">)</phrase> <phrase role="special">{</phrase>
<phrase role="keyword">int</phrase> <phrase role="identifier">idx1</phrase> <phrase role="special">=</phrase> <phrase role="special">(</phrase><phrase role="identifier">idx</phrase> <phrase role="special">+</phrase> <phrase role="number">1</phrase><phrase role="special">)</phrase> <phrase role="special">%</phrase> <phrase role="number">256</phrase><phrase role="special">;</phrase>
<phrase role="keyword">int</phrase> <phrase role="identifier">idx2</phrase> <phrase role="special">=</phrase> <phrase role="special">(</phrase><phrase role="identifier">idx</phrase> <phrase role="special">+</phrase> <phrase role="number">2</phrase><phrase role="special">)</phrase> <phrase role="special">%</phrase> <phrase role="number">256</phrase><phrase role="special">;</phrase>
<phrase role="keyword">float</phrase> <phrase role="identifier">as</phrase> <phrase role="special">=</phrase> <phrase role="special">(</phrase><phrase role="identifier">a</phrase><phrase role="special">[</phrase><phrase role="identifier">idx</phrase><phrase role="special">]</phrase> <phrase role="special">+</phrase> <phrase role="identifier">a</phrase><phrase role="special">[</phrase><phrase role="identifier">idx1</phrase><phrase role="special">]</phrase> <phrase role="special">+</phrase> <phrase role="identifier">a</phrase><phrase role="special">[</phrase><phrase role="identifier">idx2</phrase><phrase role="special">])</phrase> <phrase role="special">/</phrase> <phrase role="number">3.0f</phrase><phrase role="special">;</phrase>
<phrase role="keyword">float</phrase> <phrase role="identifier">bs</phrase> <phrase role="special">=</phrase> <phrase role="special">(</phrase><phrase role="identifier">b</phrase><phrase role="special">[</phrase><phrase role="identifier">idx</phrase><phrase role="special">]</phrase> <phrase role="special">+</phrase> <phrase role="identifier">b</phrase><phrase role="special">[</phrase><phrase role="identifier">idx1</phrase><phrase role="special">]</phrase> <phrase role="special">+</phrase> <phrase role="identifier">b</phrase><phrase role="special">[</phrase><phrase role="identifier">idx2</phrase><phrase role="special">])</phrase> <phrase role="special">/</phrase> <phrase role="number">3.0f</phrase><phrase role="special">;</phrase>
<phrase role="identifier">c</phrase><phrase role="special">[</phrase><phrase role="identifier">idx</phrase><phrase role="special">]</phrase> <phrase role="special">=</phrase> <phrase role="special">(</phrase><phrase role="identifier">as</phrase> <phrase role="special">+</phrase> <phrase role="identifier">bs</phrase><phrase role="special">)</phrase> <phrase role="special">/</phrase> <phrase role="number">2</phrase><phrase role="special">;</phrase>
<phrase role="special">}</phrase>
<phrase role="special">}</phrase>
<phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">fibers</phrase><phrase role="special">::</phrase><phrase role="identifier">fiber</phrase> <phrase role="identifier">f</phrase><phrase role="special">([&amp;</phrase><phrase role="identifier">done</phrase><phrase role="special">]{</phrase>
<phrase role="identifier">hipStream_t</phrase> <phrase role="identifier">stream</phrase><phrase role="special">;</phrase>
<phrase role="identifier">hipStreamCreate</phrase><phrase role="special">(</phrase> <phrase role="special">&amp;</phrase> <phrase role="identifier">stream</phrase><phrase role="special">);</phrase>
<phrase role="keyword">int</phrase> <phrase role="identifier">size</phrase> <phrase role="special">=</phrase> <phrase role="number">1024</phrase> <phrase role="special">*</phrase> <phrase role="number">1024</phrase><phrase role="special">;</phrase>
<phrase role="keyword">int</phrase> <phrase role="identifier">full_size</phrase> <phrase role="special">=</phrase> <phrase role="number">20</phrase> <phrase role="special">*</phrase> <phrase role="identifier">size</phrase><phrase role="special">;</phrase>
<phrase role="keyword">int</phrase> <phrase role="special">*</phrase> <phrase role="identifier">host_a</phrase><phrase role="special">,</phrase> <phrase role="special">*</phrase> <phrase role="identifier">host_b</phrase><phrase role="special">,</phrase> <phrase role="special">*</phrase> <phrase role="identifier">host_c</phrase><phrase role="special">;</phrase>
<phrase role="identifier">hipHostMalloc</phrase><phrase role="special">(</phrase> <phrase role="special">&amp;</phrase> <phrase role="identifier">host_a</phrase><phrase role="special">,</phrase> <phrase role="identifier">full_size</phrase> <phrase role="special">*</phrase> <phrase role="keyword">sizeof</phrase><phrase role="special">(</phrase> <phrase role="keyword">int</phrase><phrase role="special">),</phrase> <phrase role="identifier">hipHostMallocDefault</phrase><phrase role="special">);</phrase>
<phrase role="identifier">hipHostMalloc</phrase><phrase role="special">(</phrase> <phrase role="special">&amp;</phrase> <phrase role="identifier">host_b</phrase><phrase role="special">,</phrase> <phrase role="identifier">full_size</phrase> <phrase role="special">*</phrase> <phrase role="keyword">sizeof</phrase><phrase role="special">(</phrase> <phrase role="keyword">int</phrase><phrase role="special">),</phrase> <phrase role="identifier">hipHostMallocDefault</phrase><phrase role="special">);</phrase>
<phrase role="identifier">hipHostMalloc</phrase><phrase role="special">(</phrase> <phrase role="special">&amp;</phrase> <phrase role="identifier">host_c</phrase><phrase role="special">,</phrase> <phrase role="identifier">full_size</phrase> <phrase role="special">*</phrase> <phrase role="keyword">sizeof</phrase><phrase role="special">(</phrase> <phrase role="keyword">int</phrase><phrase role="special">),</phrase> <phrase role="identifier">hipHostMallocDefault</phrase><phrase role="special">);</phrase>
<phrase role="keyword">int</phrase> <phrase role="special">*</phrase> <phrase role="identifier">dev_a</phrase><phrase role="special">,</phrase> <phrase role="special">*</phrase> <phrase role="identifier">dev_b</phrase><phrase role="special">,</phrase> <phrase role="special">*</phrase> <phrase role="identifier">dev_c</phrase><phrase role="special">;</phrase>
<phrase role="identifier">hipMalloc</phrase><phrase role="special">(</phrase> <phrase role="special">&amp;</phrase> <phrase role="identifier">dev_a</phrase><phrase role="special">,</phrase> <phrase role="identifier">size</phrase> <phrase role="special">*</phrase> <phrase role="keyword">sizeof</phrase><phrase role="special">(</phrase> <phrase role="keyword">int</phrase><phrase role="special">)</phrase> <phrase role="special">);</phrase>
<phrase role="identifier">hipMalloc</phrase><phrase role="special">(</phrase> <phrase role="special">&amp;</phrase> <phrase role="identifier">dev_b</phrase><phrase role="special">,</phrase> <phrase role="identifier">size</phrase> <phrase role="special">*</phrase> <phrase role="keyword">sizeof</phrase><phrase role="special">(</phrase> <phrase role="keyword">int</phrase><phrase role="special">)</phrase> <phrase role="special">);</phrase>
<phrase role="identifier">hipMalloc</phrase><phrase role="special">(</phrase> <phrase role="special">&amp;</phrase> <phrase role="identifier">dev_c</phrase><phrase role="special">,</phrase> <phrase role="identifier">size</phrase> <phrase role="special">*</phrase> <phrase role="keyword">sizeof</phrase><phrase role="special">(</phrase> <phrase role="keyword">int</phrase><phrase role="special">)</phrase> <phrase role="special">);</phrase>
<phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">minstd_rand</phrase> <phrase role="identifier">generator</phrase><phrase role="special">;</phrase>
<phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">uniform_int_distribution</phrase><phrase role="special">&lt;&gt;</phrase> <phrase role="identifier">distribution</phrase><phrase role="special">(</phrase><phrase role="number">1</phrase><phrase role="special">,</phrase> <phrase role="number">6</phrase><phrase role="special">);</phrase>
<phrase role="keyword">for</phrase> <phrase role="special">(</phrase> <phrase role="keyword">int</phrase> <phrase role="identifier">i</phrase> <phrase role="special">=</phrase> <phrase role="number">0</phrase><phrase role="special">;</phrase> <phrase role="identifier">i</phrase> <phrase role="special">&lt;</phrase> <phrase role="identifier">full_size</phrase><phrase role="special">;</phrase> <phrase role="special">++</phrase><phrase role="identifier">i</phrase><phrase role="special">)</phrase> <phrase role="special">{</phrase>
<phrase role="identifier">host_a</phrase><phrase role="special">[</phrase><phrase role="identifier">i</phrase><phrase role="special">]</phrase> <phrase role="special">=</phrase> <phrase role="identifier">distribution</phrase><phrase role="special">(</phrase> <phrase role="identifier">generator</phrase><phrase role="special">);</phrase>
<phrase role="identifier">host_b</phrase><phrase role="special">[</phrase><phrase role="identifier">i</phrase><phrase role="special">]</phrase> <phrase role="special">=</phrase> <phrase role="identifier">distribution</phrase><phrase role="special">(</phrase> <phrase role="identifier">generator</phrase><phrase role="special">);</phrase>
<phrase role="special">}</phrase>
<phrase role="keyword">for</phrase> <phrase role="special">(</phrase> <phrase role="keyword">int</phrase> <phrase role="identifier">i</phrase> <phrase role="special">=</phrase> <phrase role="number">0</phrase><phrase role="special">;</phrase> <phrase role="identifier">i</phrase> <phrase role="special">&lt;</phrase> <phrase role="identifier">full_size</phrase><phrase role="special">;</phrase> <phrase role="identifier">i</phrase> <phrase role="special">+=</phrase> <phrase role="identifier">size</phrase><phrase role="special">)</phrase> <phrase role="special">{</phrase>
<phrase role="identifier">hipMemcpyAsync</phrase><phrase role="special">(</phrase> <phrase role="identifier">dev_a</phrase><phrase role="special">,</phrase> <phrase role="identifier">host_a</phrase> <phrase role="special">+</phrase> <phrase role="identifier">i</phrase><phrase role="special">,</phrase> <phrase role="identifier">size</phrase> <phrase role="special">*</phrase> <phrase role="keyword">sizeof</phrase><phrase role="special">(</phrase> <phrase role="keyword">int</phrase><phrase role="special">),</phrase> <phrase role="identifier">hipMemcpyHostToDevice</phrase><phrase role="special">,</phrase> <phrase role="identifier">stream</phrase><phrase role="special">);</phrase>
<phrase role="identifier">hipMemcpyAsync</phrase><phrase role="special">(</phrase> <phrase role="identifier">dev_b</phrase><phrase role="special">,</phrase> <phrase role="identifier">host_b</phrase> <phrase role="special">+</phrase> <phrase role="identifier">i</phrase><phrase role="special">,</phrase> <phrase role="identifier">size</phrase> <phrase role="special">*</phrase> <phrase role="keyword">sizeof</phrase><phrase role="special">(</phrase> <phrase role="keyword">int</phrase><phrase role="special">),</phrase> <phrase role="identifier">hipMemcpyHostToDevice</phrase><phrase role="special">,</phrase> <phrase role="identifier">stream</phrase><phrase role="special">);</phrase>
<phrase role="identifier">hipLaunchKernel</phrase><phrase role="special">(</phrase><phrase role="identifier">kernel</phrase><phrase role="special">,</phrase> <phrase role="identifier">dim3</phrase><phrase role="special">(</phrase><phrase role="identifier">size</phrase> <phrase role="special">/</phrase> <phrase role="number">256</phrase><phrase role="special">),</phrase> <phrase role="identifier">dim3</phrase><phrase role="special">(</phrase><phrase role="number">256</phrase><phrase role="special">),</phrase> <phrase role="number">0</phrase><phrase role="special">,</phrase> <phrase role="identifier">stream</phrase><phrase role="special">,</phrase> <phrase role="identifier">size</phrase><phrase role="special">,</phrase> <phrase role="identifier">dev_a</phrase><phrase role="special">,</phrase> <phrase role="identifier">dev_b</phrase><phrase role="special">,</phrase> <phrase role="identifier">dev_c</phrase><phrase role="special">);</phrase>
<phrase role="identifier">hipMemcpyAsync</phrase><phrase role="special">(</phrase> <phrase role="identifier">host_c</phrase> <phrase role="special">+</phrase> <phrase role="identifier">i</phrase><phrase role="special">,</phrase> <phrase role="identifier">dev_c</phrase><phrase role="special">,</phrase> <phrase role="identifier">size</phrase> <phrase role="special">*</phrase> <phrase role="keyword">sizeof</phrase><phrase role="special">(</phrase> <phrase role="keyword">int</phrase><phrase role="special">),</phrase> <phrase role="identifier">hipMemcpyDeviceToHost</phrase><phrase role="special">,</phrase> <phrase role="identifier">stream</phrase><phrase role="special">);</phrase>
<phrase role="special">}</phrase>
<phrase role="keyword">auto</phrase> <phrase role="identifier">result</phrase> <phrase role="special">=</phrase> <phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">fibers</phrase><phrase role="special">::</phrase><phrase role="identifier">hip</phrase><phrase role="special">::</phrase><phrase role="identifier">waitfor_all</phrase><phrase role="special">(</phrase> <phrase role="identifier">stream</phrase><phrase role="special">);</phrase> <phrase role="comment">// suspend fiber till HIP stream has finished</phrase>
<phrase role="identifier">BOOST_ASSERT</phrase><phrase role="special">(</phrase> <phrase role="identifier">stream</phrase> <phrase role="special">==</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">get</phrase><phrase role="special">&lt;</phrase> <phrase role="number">0</phrase> <phrase role="special">&gt;(</phrase> <phrase role="identifier">result</phrase><phrase role="special">)</phrase> <phrase role="special">);</phrase>
<phrase role="identifier">BOOST_ASSERT</phrase><phrase role="special">(</phrase> <phrase role="identifier">hipSuccess</phrase> <phrase role="special">==</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">get</phrase><phrase role="special">&lt;</phrase> <phrase role="number">1</phrase> <phrase role="special">&gt;(</phrase> <phrase role="identifier">result</phrase><phrase role="special">)</phrase> <phrase role="special">);</phrase>
<phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">cout</phrase> <phrase role="special">&lt;&lt;</phrase> <phrase role="string">&quot;f1: GPU computation finished&quot;</phrase> <phrase role="special">&lt;&lt;</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">endl</phrase><phrase role="special">;</phrase>
<phrase role="identifier">hipHostFree</phrase><phrase role="special">(</phrase> <phrase role="identifier">host_a</phrase><phrase role="special">);</phrase>
<phrase role="identifier">hipHostFree</phrase><phrase role="special">(</phrase> <phrase role="identifier">host_b</phrase><phrase role="special">);</phrase>
<phrase role="identifier">hipHostFree</phrase><phrase role="special">(</phrase> <phrase role="identifier">host_c</phrase><phrase role="special">);</phrase>
<phrase role="identifier">hipFree</phrase><phrase role="special">(</phrase> <phrase role="identifier">dev_a</phrase><phrase role="special">);</phrase>
<phrase role="identifier">hipFree</phrase><phrase role="special">(</phrase> <phrase role="identifier">dev_b</phrase><phrase role="special">);</phrase>
<phrase role="identifier">hipFree</phrase><phrase role="special">(</phrase> <phrase role="identifier">dev_c</phrase><phrase role="special">);</phrase>
<phrase role="identifier">hipStreamDestroy</phrase><phrase role="special">(</phrase> <phrase role="identifier">stream</phrase><phrase role="special">);</phrase>
<phrase role="special">});</phrase>
<phrase role="identifier">f</phrase><phrase role="special">.</phrase><phrase role="identifier">join</phrase><phrase role="special">();</phrase>
</programlisting>
<bridgehead renderas="sect4" id="fiber.gpu_computing.hip.h1">
<phrase id="fiber.gpu_computing.hip.synopsis"/><link linkend="fiber.gpu_computing.hip.synopsis">Synopsis</link>
</bridgehead>
<programlisting><phrase role="preprocessor">#include</phrase> <phrase role="special">&lt;</phrase><phrase role="identifier">boost</phrase><phrase role="special">/</phrase><phrase role="identifier">fiber</phrase><phrase role="special">/</phrase><phrase role="identifier">hip</phrase><phrase role="special">/</phrase><phrase role="identifier">waitfor</phrase><phrase role="special">.</phrase><phrase role="identifier">hpp</phrase><phrase role="special">&gt;</phrase>
<phrase role="keyword">namespace</phrase> <phrase role="identifier">boost</phrase> <phrase role="special">{</phrase>
<phrase role="keyword">namespace</phrase> <phrase role="identifier">fibers</phrase> <phrase role="special">{</phrase>
<phrase role="keyword">namespace</phrase> <phrase role="identifier">hip</phrase> <phrase role="special">{</phrase>
<phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">tuple</phrase><phrase role="special">&lt;</phrase> <phrase role="identifier">hipStream_t</phrase><phrase role="special">,</phrase> <phrase role="identifier">hipError_t</phrase> <phrase role="special">&gt;</phrase> <phrase role="identifier">waitfor_all</phrase><phrase role="special">(</phrase> <phrase role="identifier">hipStream_t</phrase> <phrase role="identifier">st</phrase><phrase role="special">);</phrase>
<phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">vector</phrase><phrase role="special">&lt;</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">tuple</phrase><phrase role="special">&lt;</phrase> <phrase role="identifier">hipStream_t</phrase><phrase role="special">,</phrase> <phrase role="identifier">hipError_t</phrase> <phrase role="special">&gt;</phrase> <phrase role="special">&gt;</phrase> <phrase role="identifier">waitfor_all</phrase><phrase role="special">(</phrase> <phrase role="identifier">hipStream_t</phrase> <phrase role="special">...</phrase> <phrase role="identifier">st</phrase><phrase role="special">);</phrase>
<phrase role="special">}}}</phrase>
</programlisting>
<para>
<bridgehead renderas="sect4" id="hip_waitfor_bridgehead">
<phrase id="hip_waitfor"/>
<link linkend="hip_waitfor">Non-member function <code>hip::waitfor()</code></link>
</bridgehead>
</para>
<programlisting><phrase role="preprocessor">#include</phrase> <phrase role="special">&lt;</phrase><phrase role="identifier">boost</phrase><phrase role="special">/</phrase><phrase role="identifier">fiber</phrase><phrase role="special">/</phrase><phrase role="identifier">hip</phrase><phrase role="special">/</phrase><phrase role="identifier">waitfor</phrase><phrase role="special">.</phrase><phrase role="identifier">hpp</phrase><phrase role="special">&gt;</phrase>
<phrase role="keyword">namespace</phrase> <phrase role="identifier">boost</phrase> <phrase role="special">{</phrase>
<phrase role="keyword">namespace</phrase> <phrase role="identifier">fibers</phrase> <phrase role="special">{</phrase>
<phrase role="keyword">namespace</phrase> <phrase role="identifier">hip</phrase> <phrase role="special">{</phrase>
<phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">tuple</phrase><phrase role="special">&lt;</phrase> <phrase role="identifier">hipStream_t</phrase><phrase role="special">,</phrase> <phrase role="identifier">hipError_t</phrase> <phrase role="special">&gt;</phrase> <phrase role="identifier">waitfor_all</phrase><phrase role="special">(</phrase> <phrase role="identifier">hipStream_t</phrase> <phrase role="identifier">st</phrase><phrase role="special">);</phrase>
<phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">vector</phrase><phrase role="special">&lt;</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">tuple</phrase><phrase role="special">&lt;</phrase> <phrase role="identifier">hipStream_t</phrase><phrase role="special">,</phrase> <phrase role="identifier">hipError_t</phrase> <phrase role="special">&gt;</phrase> <phrase role="special">&gt;</phrase> <phrase role="identifier">waitfor_all</phrase><phrase role="special">(</phrase> <phrase role="identifier">hipStream_t</phrase> <phrase role="special">...</phrase> <phrase role="identifier">st</phrase><phrase role="special">);</phrase>
<phrase role="special">}}}</phrase>
</programlisting>
<variablelist>
<title></title>
<varlistentry>
<term>Effects:</term>
<listitem>
<para>
Suspends active fiber till HIP stream has finished its operations.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>Returns:</term>
<listitem>
<para>
tuple of stream reference and the HIP stream status
</para>
</listitem>
</varlistentry>
</variablelist>
</section>
</section>
<section id="fiber.worker">
<title><anchor id="worker"/><link linkend="fiber.worker">Running with worker
threads</link></title>
<bridgehead renderas="sect3" id="fiber.worker.h0">
<phrase id="fiber.worker.keep_workers_running"/><link linkend="fiber.worker.keep_workers_running">Keep
workers running</link>
</bridgehead>
<para>
If a worker thread is used but no fiber is created or parts of the framework
(like <link linkend="this_fiber_yield"><code>this_fiber::yield()</code></link>) are touched, then no fiber scheduler
is instantiated.
</para>
<programlisting><phrase role="keyword">auto</phrase> <phrase role="identifier">worker</phrase> <phrase role="special">=</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">thread</phrase><phrase role="special">(</phrase>
<phrase role="special">[]{</phrase>
<phrase role="comment">// fiber scheduler not instantiated</phrase>
<phrase role="special">});</phrase>
<phrase role="identifier">worker</phrase><phrase role="special">.</phrase><phrase role="identifier">join</phrase><phrase role="special">();</phrase>
</programlisting>
<para>
If <emphasis>use_scheduling_algorithm&lt;&gt;()</emphasis> is invoked, the
fiber scheduler is created. If the worker thread simply returns, destroys the
scheduler and terminates.
</para>
<programlisting><phrase role="keyword">auto</phrase> <phrase role="identifier">worker</phrase> <phrase role="special">=</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">thread</phrase><phrase role="special">(</phrase>
<phrase role="special">[]{</phrase>
<phrase role="comment">// fiber scheduler created</phrase>
<phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">fibers</phrase><phrase role="special">::</phrase><phrase role="identifier">use_scheduling_algorithm</phrase><phrase role="special">&lt;</phrase><phrase role="identifier">my_fiber_scheduler</phrase><phrase role="special">&gt;();</phrase>
<phrase role="special">});</phrase>
<phrase role="identifier">worker</phrase><phrase role="special">.</phrase><phrase role="identifier">join</phrase><phrase role="special">();</phrase>
</programlisting>
<para>
In order to keep the worker thread running, the fiber associated with the thread
stack (which is called <quote>main</quote> fiber) is blocked. For instance
the <quote>main</quote> fiber might wait on a <link linkend="class_condition_variable"><code>condition_variable</code></link>.
For a gracefully shutdown <link linkend="class_condition_variable"><code>condition_variable</code></link> is signalled
and the <quote>main</quote> fiber returns. The scheduler gets destructed if
all fibers of the worker thread have been terminated.
</para>
<programlisting><phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">fibers</phrase><phrase role="special">::</phrase><phrase role="identifier">mutex</phrase> <phrase role="identifier">mtx</phrase><phrase role="special">;</phrase>
<phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">fibers</phrase><phrase role="special">::</phrase><phrase role="identifier">condition_variable_any</phrase> <phrase role="identifier">cv</phrase><phrase role="special">;</phrase>
<phrase role="keyword">auto</phrase> <phrase role="identifier">worker</phrase> <phrase role="special">=</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">thread</phrase><phrase role="special">(</phrase>
<phrase role="special">[&amp;</phrase><phrase role="identifier">mtx</phrase><phrase role="special">,&amp;</phrase><phrase role="identifier">cv</phrase><phrase role="special">]{</phrase>
<phrase role="identifier">mtx</phrase><phrase role="special">.</phrase><phrase role="identifier">lock</phrase><phrase role="special">();</phrase>
<phrase role="comment">// suspend till signalled</phrase>
<phrase role="identifier">cv</phrase><phrase role="special">.</phrase><phrase role="identifier">wait</phrase><phrase role="special">(</phrase><phrase role="identifier">mtx</phrase><phrase role="special">);</phrase>
<phrase role="identifier">mtx</phrase><phrase role="special">.</phrase><phrase role="identifier">unlock</phrase><phrase role="special">();</phrase>
<phrase role="special">});</phrase>
<phrase role="comment">// signal termination</phrase>
<phrase role="identifier">cv</phrase><phrase role="special">.</phrase><phrase role="identifier">notify_all</phrase><phrase role="special">();</phrase>
<phrase role="identifier">worker</phrase><phrase role="special">.</phrase><phrase role="identifier">join</phrase><phrase role="special">();</phrase>
</programlisting>
<bridgehead renderas="sect3" id="fiber.worker.h1">
<phrase id="fiber.worker.processing_tasks"/><link linkend="fiber.worker.processing_tasks">Processing
tasks</link>
</bridgehead>
<para>
Tasks can be transferred via channels. The worker thread runs a pool of fibers
that dequeue and executed tasks from the channel. The termination is signalled
via closing the channel.
</para>
<programlisting><phrase role="keyword">using</phrase> <phrase role="identifier">task</phrase> <phrase role="special">=</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">function</phrase><phrase role="special">&lt;</phrase><phrase role="keyword">void</phrase><phrase role="special">()&gt;;</phrase>
<phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">fibers</phrase><phrase role="special">::</phrase><phrase role="identifier">buffered_channel</phrase><phrase role="special">&lt;</phrase><phrase role="identifier">task</phrase><phrase role="special">&gt;</phrase> <phrase role="identifier">ch</phrase><phrase role="special">{</phrase><phrase role="number">1024</phrase><phrase role="special">};</phrase>
<phrase role="keyword">auto</phrase> <phrase role="identifier">worker</phrase> <phrase role="special">=</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">thread</phrase><phrase role="special">(</phrase>
<phrase role="special">[&amp;</phrase><phrase role="identifier">ch</phrase><phrase role="special">]{</phrase>
<phrase role="comment">// create pool of fibers</phrase>
<phrase role="keyword">for</phrase> <phrase role="special">(</phrase><phrase role="keyword">int</phrase> <phrase role="identifier">i</phrase><phrase role="special">=</phrase><phrase role="number">0</phrase><phrase role="special">;</phrase> <phrase role="identifier">i</phrase><phrase role="special">&lt;</phrase><phrase role="number">10</phrase><phrase role="special">;</phrase> <phrase role="special">++</phrase><phrase role="identifier">i</phrase><phrase role="special">)</phrase> <phrase role="special">{</phrase>
<phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">fibers</phrase><phrase role="special">::</phrase><phrase role="identifier">fiber</phrase><phrase role="special">{</phrase>
<phrase role="special">[&amp;</phrase><phrase role="identifier">ch</phrase><phrase role="special">]{</phrase>
<phrase role="identifier">task</phrase> <phrase role="identifier">tsk</phrase><phrase role="special">;</phrase>
<phrase role="comment">// dequeue and process tasks</phrase>
<phrase role="keyword">while</phrase> <phrase role="special">(</phrase><phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">fibers</phrase><phrase role="special">::</phrase><phrase role="identifier">channel_op_status</phrase><phrase role="special">::</phrase><phrase role="identifier">closed</phrase><phrase role="special">!=</phrase><phrase role="identifier">ch</phrase><phrase role="special">.</phrase><phrase role="identifier">pop</phrase><phrase role="special">(</phrase><phrase role="identifier">tsk</phrase><phrase role="special">)){</phrase>
<phrase role="identifier">tsk</phrase><phrase role="special">();</phrase>
<phrase role="special">}</phrase>
<phrase role="special">}}.</phrase><phrase role="identifier">detach</phrase><phrase role="special">();</phrase>
<phrase role="special">}</phrase>
<phrase role="identifier">task</phrase> <phrase role="identifier">tsk</phrase><phrase role="special">;</phrase>
<phrase role="comment">// dequeue and process tasks</phrase>
<phrase role="keyword">while</phrase> <phrase role="special">(</phrase><phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">fibers</phrase><phrase role="special">::</phrase><phrase role="identifier">channel_op_status</phrase><phrase role="special">::</phrase><phrase role="identifier">closed</phrase><phrase role="special">!=</phrase><phrase role="identifier">ch</phrase><phrase role="special">.</phrase><phrase role="identifier">pop</phrase><phrase role="special">(</phrase><phrase role="identifier">tsk</phrase><phrase role="special">)){</phrase>
<phrase role="identifier">tsk</phrase><phrase role="special">();</phrase>
<phrase role="special">}</phrase>
<phrase role="special">});</phrase>
<phrase role="comment">// feed channel with tasks</phrase>
<phrase role="identifier">ch</phrase><phrase role="special">.</phrase><phrase role="identifier">push</phrase><phrase role="special">([]{</phrase> <phrase role="special">...</phrase> <phrase role="special">});</phrase>
<phrase role="special">...</phrase>
<phrase role="comment">// signal termination</phrase>
<phrase role="identifier">ch</phrase><phrase role="special">.</phrase><phrase role="identifier">close</phrase><phrase role="special">();</phrase>
<phrase role="identifier">worker</phrase><phrase role="special">.</phrase><phrase role="identifier">join</phrase><phrase role="special">();</phrase>
</programlisting>
<para>
An alternative is to use a work-stealing scheduler. This kind of scheduling
algorithm a worker thread steals fibers from the ready-queue of other worker
threads if its own ready-queue is empty.
</para>
<note>
<para>
Wait till all worker threads have registered the work-stealing scheduling
algorithm.
</para>
</note>
<programlisting><phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">fibers</phrase><phrase role="special">::</phrase><phrase role="identifier">mutex</phrase> <phrase role="identifier">mtx</phrase><phrase role="special">;</phrase>
<phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">fibers</phrase><phrase role="special">::</phrase><phrase role="identifier">condition_variable_any</phrase> <phrase role="identifier">cv</phrase><phrase role="special">;</phrase>
<phrase role="comment">// start wotrker-thread first</phrase>
<phrase role="keyword">auto</phrase> <phrase role="identifier">worker</phrase> <phrase role="special">=</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">thread</phrase><phrase role="special">(</phrase>
<phrase role="special">[&amp;</phrase><phrase role="identifier">mtx</phrase><phrase role="special">,&amp;</phrase><phrase role="identifier">cv</phrase><phrase role="special">]{</phrase>
<phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">fibers</phrase><phrase role="special">::</phrase><phrase role="identifier">use_scheduling_algorithm</phrase><phrase role="special">&lt;</phrase><phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">fibers</phrase><phrase role="special">::</phrase><phrase role="identifier">algo</phrase><phrase role="special">::</phrase><phrase role="identifier">work_stealing</phrase><phrase role="special">&gt;(</phrase><phrase role="number">2</phrase><phrase role="special">);</phrase>
<phrase role="identifier">mtx</phrase><phrase role="special">.</phrase><phrase role="identifier">lock</phrase><phrase role="special">();</phrase>
<phrase role="comment">// suspend main-fiber from the worker thread</phrase>
<phrase role="identifier">cv</phrase><phrase role="special">.</phrase><phrase role="identifier">wait</phrase><phrase role="special">(</phrase><phrase role="identifier">mtx</phrase><phrase role="special">);</phrase>
<phrase role="identifier">mtx</phrase><phrase role="special">.</phrase><phrase role="identifier">unlock</phrase><phrase role="special">();</phrase>
<phrase role="special">});</phrase>
<phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">fibers</phrase><phrase role="special">::</phrase><phrase role="identifier">use_scheduling_algorithm</phrase><phrase role="special">&lt;</phrase><phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">fibers</phrase><phrase role="special">::</phrase><phrase role="identifier">algo</phrase><phrase role="special">::</phrase><phrase role="identifier">work_stealing</phrase><phrase role="special">&gt;(</phrase><phrase role="number">2</phrase><phrase role="special">);</phrase>
<phrase role="comment">// create fibers with tasks</phrase>
<phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">fibers</phrase><phrase role="special">::</phrase><phrase role="identifier">fiber</phrase> <phrase role="identifier">f</phrase><phrase role="special">{[]{</phrase> <phrase role="special">...</phrase> <phrase role="special">}};</phrase>
<phrase role="special">...</phrase>
<phrase role="comment">// signal termination</phrase>
<phrase role="identifier">cv</phrase><phrase role="special">.</phrase><phrase role="identifier">notify_all</phrase><phrase role="special">();</phrase>
<phrase role="identifier">worker</phrase><phrase role="special">.</phrase><phrase role="identifier">join</phrase><phrase role="special">();</phrase>
</programlisting>
<important>
<para>
Because the TIB (thread information block on Windows) is not fully described
in the MSDN, it might be possible that not all required TIB-parts are swapped.
Using WinFiber implementation might be an alternative (see documentation
about <ulink url="http://www.boost.org/doc/libs/1_65_1/libs/context/doc/html/context/cc/implementations__fcontext_t__ucontext_t_and_winfiber.html"><emphasis>implementations
fcontext_t, ucontext_t and WinFiber of boost.context</emphasis></ulink>).
</para>
</important>
</section>
<section id="fiber.performance">
<title><link linkend="fiber.performance">Performance</link></title>
<para>
Performance measurements were taken using <code><phrase role="identifier">std</phrase><phrase
role="special">::</phrase><phrase role="identifier">chrono</phrase><phrase
role="special">::</phrase><phrase role="identifier">highresolution_clock</phrase></code>,
with overhead corrections. The code was compiled with gcc-6.3.1, using build
options: variant = release, optimization = speed. Tests were executed on dual
Intel XEON E5 2620v4 2.2GHz, 16C/32T, 64GB RAM, running Linux (x86_64).
</para>
<para>
Measurements headed 1C/1T were run in a single-threaded process.
</para>
<para>
The <ulink url="https://github.com/atemerev/skynet">microbenchmark <emphasis>syknet</emphasis></ulink>
from Alexander Temerev was ported and used for performance measurements. At
the root the test spawns 10 threads-of-execution (ToE), e.g. actor/goroutine/fiber
etc.. Each spawned ToE spawns additional 10 ToEs ... until <emphasis role="bold">1,000,000</emphasis>
ToEs are created. ToEs return back their ordinal numbers (0 ... 999,999), which
are summed on the previous level and sent back upstream, until reaching the
root. The test was run 10-20 times, producing a range of values for each measurement.
</para>
<table frame="all" id="fiber.performance.time_per_actor_erlang_process_goroutine__other_languages___average_over_1_000_000_">
<title>time per actor/erlang process/goroutine (other languages) (average over
1,000,000)</title>
<tgroup cols="3">
<thead>
<row>
<entry>
<para>
Haskell | stack-1.4.0/ghc-8.0.1
</para>
</entry>
<entry>
<para>
Go | go1.8.1
</para>
</entry>
<entry>
<para>
Erlang | erts-8.3
</para>
</entry>
</row>
</thead>
<tbody>
<row>
<entry>
<para>
0.05 &#xb5;s - 0.06 &#xb5;s
</para>
</entry>
<entry>
<para>
0.42 &#xb5;s - 0.49 &#xb5;s
</para>
</entry>
<entry>
<para>
0.63 &#xb5;s - 0.73 &#xb5;s
</para>
</entry>
</row>
</tbody>
</tgroup>
</table>
<para>
Pthreads are created with a stack size of 8kB while <code><phrase role="identifier">std</phrase><phrase
role="special">::</phrase><phrase role="identifier">thread</phrase></code>'s
use the system default (1MB - 2MB). The microbenchmark could <emphasis role="bold">not</emphasis>
be <emphasis role="bold">run</emphasis> with 1,000,000 threads because of
<emphasis role="bold">resource exhaustion</emphasis> (pthread and std::thread).
Instead the test runs only at <emphasis role="bold">10,000</emphasis> threads.
</para>
<table frame="all" id="fiber.performance.time_per_thread__average_over_10_000___unable_to_spawn_1_000_000_threads_">
<title>time per thread (average over 10,000 - unable to spawn 1,000,000 threads)</title>
<tgroup cols="3">
<thead>
<row>
<entry>
<para>
pthread
</para>
</entry>
<entry>
<para>
<code><phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase
role="identifier">thread</phrase></code>
</para>
</entry>
<entry>
<para>
<code><phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase
role="identifier">async</phrase></code>
</para>
</entry>
</row>
</thead>
<tbody>
<row>
<entry>
<para>
54 &#xb5;s - 73 &#xb5;s
</para>
</entry>
<entry>
<para>
52 &#xb5;s - 73 &#xb5;s
</para>
</entry>
<entry>
<para>
106 &#xb5;s - 122 &#xb5;s
</para>
</entry>
</row>
</tbody>
</tgroup>
</table>
<para>
The test utilizes 16 cores with Symmetric MultiThreading enabled (32 logical
CPUs). The fiber stacks are allocated by <link linkend="class_fixedsize_stack"><code>fixedsize_stack</code></link>.
</para>
<para>
As the benchmark shows, the memory allocation algorithm is significant for
performance in a multithreaded environment. The tests use glibc&#8217;s memory allocation
algorithm (based on ptmalloc2) as well as Google&#8217;s <ulink url="http://goog-perftools.sourceforge.net/doc/tcmalloc.html">TCmalloc</ulink>
(via linkflags=&quot;-ltcmalloc&quot;).<footnote id="fiber.performance.f0">
<para>
Tais B. Ferreira, Rivalino Matias, Autran Macedo, Lucio B. Araujo <quote>An
Experimental Study on Memory Allocators in Multicore and Multithreaded Applications</quote>,
PDCAT &#8217;11 Proceedings of the 2011 12th International Conference on Parallel
and Distributed Computing, Applications and Technologies, pages 92-98
</para>
</footnote>
</para>
<para>
In the <link linkend="class_work_stealing"><code>work_stealing</code></link> scheduling algorithm, each thread has
its own local queue. Fibers that are ready to run are pushed to and popped
from the local queue. If the queue runs out of ready fibers, fibers are stolen
from the local queues of other participating threads.
</para>
<table frame="all" id="fiber.performance.time_per_fiber__average_over_1_000_000_">
<title>time per fiber (average over 1.000.000)</title>
<tgroup cols="2">
<thead>
<row>
<entry>
<para>
fiber (16C/32T, work stealing, tcmalloc)
</para>
</entry>
<entry>
<para>
fiber (1C/1T, round robin, tcmalloc)
</para>
</entry>
</row>
</thead>
<tbody>
<row>
<entry>
<para>
0.05 &#xb5;s - 0.09 &#xb5;s
</para>
</entry>
<entry>
<para>
1.69 &#xb5;s - 1.79 &#xb5;s
</para>
</entry>
</row>
</tbody>
</tgroup>
</table>
</section>
<section id="fiber.tuning">
<title><anchor id="tuning"/><link linkend="fiber.tuning">Tuning</link></title>
<bridgehead renderas="sect3" id="fiber.tuning.h0">
<phrase id="fiber.tuning.disable_synchronization"/><link linkend="fiber.tuning.disable_synchronization">Disable
synchronization</link>
</bridgehead>
<para>
With <link linkend="cross_thread_sync"><code><phrase role="identifier">BOOST_FIBERS_NO_ATOMICS</phrase></code></link>
defined at the compiler&#8217;s command line, synchronization between fibers (in different
threads) is disabled. This is acceptable if the application is single threaded
and/or fibers are not synchronized between threads.
</para>
<bridgehead renderas="sect3" id="fiber.tuning.h1">
<phrase id="fiber.tuning.memory_allocation"/><link linkend="fiber.tuning.memory_allocation">Memory
allocation</link>
</bridgehead>
<para>
Memory allocation algorithm is significant for performance in a multithreaded
environment, especially for <emphasis role="bold">Boost.Fiber</emphasis> where
fiber stacks are allocated on the heap. The default user-level memory allocator
(UMA) of glibc is ptmalloc2 but it can be replaced by another UMA that fit
better for the concret work-load For instance Google&#8217;s <ulink url="http://goog-perftools.sourceforge.net/doc/tcmalloc.html">TCmalloc</ulink>
enables a better performance at the <emphasis>skynet</emphasis> microbenchmark
than glibc&#8217;s default memory allocator.
</para>
<bridgehead renderas="sect3" id="fiber.tuning.h2">
<phrase id="fiber.tuning.scheduling_strategies"/><link linkend="fiber.tuning.scheduling_strategies">Scheduling
strategies</link>
</bridgehead>
<para>
The fibers in a thread are coordinated by a fiber manager. Fibers trade control
cooperatively, rather than preemptively. Depending on the work-load several
strategies of scheduling the fibers are possible <footnote id="fiber.tuning.f0">
<para>
1024cores.net: <ulink url="http://www.1024cores.net/home/scalable-architecture/task-scheduling-strategies">Task
Scheduling Strategies</ulink>
</para>
</footnote> that can be implmented on behalf of <link linkend="class_algorithm"><code>algorithm</code></link>.
</para>
<itemizedlist>
<listitem>
<simpara>
work-stealing: ready fibers are hold in a local queue, when the fiber-scheduler's
local queue runs out of ready fibers, it randomly selects another fiber-scheduler
and tries to steal a ready fiber from the victim (implemented in <link linkend="class_work_stealing"><code>work_stealing</code></link> and
<link linkend="class_numa_work_stealing"><code>numa::work_stealing</code></link>)
</simpara>
</listitem>
<listitem>
<simpara>
work-requesting: ready fibers are hold in a local queue, when the fiber-scheduler's
local queue runs out of ready fibers, it randomly selects another fiber-scheduler
and requests for a ready fibers, the victim fiber-scheduler sends a ready-fiber
back
</simpara>
</listitem>
<listitem>
<simpara>
work-sharing: ready fibers are hold in a global queue, fiber-scheduler
concurrently push and pop ready fibers to/from the global queue (implemented
in <link linkend="class_shared_work"><code>shared_work</code></link>)
</simpara>
</listitem>
<listitem>
<simpara>
work-distribution: fibers that became ready are proactivly distributed
to idle fiber-schedulers or fiber-schedulers with low load
</simpara>
</listitem>
<listitem>
<simpara>
work-balancing: a dedicated (helper) fiber-scheduler periodically collects
informations about all fiber-scheduler running in other threads and re-distributes
ready fibers among them
</simpara>
</listitem>
</itemizedlist>
<bridgehead renderas="sect3" id="fiber.tuning.h3">
<phrase id="fiber.tuning.ttas_locks"/><link linkend="fiber.tuning.ttas_locks">TTAS
locks</link>
</bridgehead>
<para>
Boost.Fiber uses internally spinlocks to protect critical regions if fibers
running on different threads interact. Spinlocks are implemented as TTAS (test-test-and-set)
locks, i.e. the spinlock tests the lock before calling an atomic exchange.
This strategy helps to reduce the cache line invalidations triggered by acquiring/releasing
the lock.
</para>
<bridgehead renderas="sect3" id="fiber.tuning.h4">
<phrase id="fiber.tuning.spin_wait_loop"/><link linkend="fiber.tuning.spin_wait_loop">Spin-wait
loop</link>
</bridgehead>
<para>
A lock is considered under contention, if a thread repeatedly fails to acquire
the lock because some other thread was faster. Waiting for a short time lets
other threads finish before trying to enter the critical section again. While
busy waiting on the lock, relaxing the CPU (via pause/yield mnemonic) gives
the CPU a hint that the code is in a spin-wait loop.
</para>
<itemizedlist>
<listitem>
<simpara>
prevents expensive pipeline flushes (speculatively executed load and compare
instructions are not pushed to pipeline)
</simpara>
</listitem>
<listitem>
<simpara>
another hardware thread (simultaneous multithreading) can get time slice
</simpara>
</listitem>
<listitem>
<simpara>
it does delay a few CPU cycles, but this is necessary to prevent starvation
</simpara>
</listitem>
</itemizedlist>
<para>
It is obvious that this strategy is useless on single core systems because
the lock can only released if the thread gives up its time slice in order to
let other threads run. The macro BOOST_FIBERS_SPIN_SINGLE_CORE replaces the
CPU hints (pause/yield mnemonic) by informing the operating system (via <code><phrase
role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">this_thread_yield</phrase><phrase
role="special">()</phrase></code>) that the thread gives up its time slice
and the operating system switches to another thread.
</para>
<bridgehead renderas="sect3" id="fiber.tuning.h5">
<phrase id="fiber.tuning.exponential_back_off"/><link linkend="fiber.tuning.exponential_back_off">Exponential
back-off</link>
</bridgehead>
<para>
The macro BOOST_FIBERS_RETRY_THRESHOLD determines how many times the CPU iterates
in the spin-wait loop before yielding the thread or blocking in futex-wait.
The spinlock tracks how many times the thread failed to acquire the lock. The
higher the contention, the longer the thread should back-off. A <quote>Binary
Exponential Backoff</quote> algorithm together with a randomized contention
window is utilized for this purpose. BOOST_FIBERS_CONTENTION_WINDOW_THRESHOLD
determines the upper limit of the contention window (expressed as the exponent
for basis of two).
</para>
<bridgehead renderas="sect3" id="fiber.tuning.h6">
<phrase id="fiber.tuning.speculative_execution__hardware_transactional_memory_"/><link
linkend="fiber.tuning.speculative_execution__hardware_transactional_memory_">Speculative
execution (hardware transactional memory)</link>
</bridgehead>
<para>
Boost.Fiber uses spinlocks to protect critical regions that can be used together
with transactional memory (see section <link linkend="speculation">Speculative
execution</link>).
</para>
<note>
<para>
TXS is enabled if property <code><phrase role="identifier">htm</phrase><phrase
role="special">=</phrase><phrase role="identifier">tsx</phrase></code> is
specified at b2 command-line and <code><phrase role="identifier">BOOST_USE_TSX</phrase></code>
is applied to the compiler.
</para>
</note>
<note>
<para>
A TSX-transaction will be aborted if the floating point state is modified
inside a critical region. As a consequence floating point operations, e.g.
tore/load of floating point related registers during a fiber (context) switch
are disabled.
</para>
</note>
<bridgehead renderas="sect3" id="fiber.tuning.h7">
<phrase id="fiber.tuning.numa_systems"/><link linkend="fiber.tuning.numa_systems">NUMA
systems</link>
</bridgehead>
<para>
Modern multi-socket systems are usually designed as <link linkend="numa">NUMA
systems</link>. A suitable fiber scheduler like <link linkend="class_numa_work_stealing"><code>numa::work_stealing</code></link> reduces
remote memory access (latence).
</para>
<bridgehead renderas="sect3" id="fiber.tuning.h8">
<phrase id="fiber.tuning.parameters"/><link linkend="fiber.tuning.parameters">Parameters</link>
</bridgehead>
<table frame="all" id="fiber.tuning.parameters_that_migh_be_defiend_at_compiler_s_command_line">
<title>Parameters that migh be defiend at compiler's command line</title>
<tgroup cols="3">
<thead>
<row>
<entry>
<para>
Parameter
</para>
</entry>
<entry>
<para>
Default value
</para>
</entry>
<entry>
<para>
Effect on Boost.Fiber
</para>
</entry>
</row>
</thead>
<tbody>
<row>
<entry>
<para>
BOOST_FIBERS_NO_ATOMICS
</para>
</entry>
<entry>
<para>
-
</para>
</entry>
<entry>
<para>
no multithreading support, all atomics removed, no synchronization
between fibers running in different threads
</para>
</entry>
</row>
<row>
<entry>
<para>
BOOST_FIBERS_SPINLOCK_STD_MUTEX
</para>
</entry>
<entry>
<para>
-
</para>
</entry>
<entry>
<para>
<code><phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase
role="identifier">mutex</phrase></code> used inside spinlock
</para>
</entry>
</row>
<row>
<entry>
<para>
BOOST_FIBERS_SPINLOCK_TTAS
</para>
</entry>
<entry>
<para>
+
</para>
</entry>
<entry>
<para>
spinlock with test-test-and-swap on shared variable
</para>
</entry>
</row>
<row>
<entry>
<para>
BOOST_FIBERS_SPINLOCK_TTAS_ADAPTIVE
</para>
</entry>
<entry>
<para>
-
</para>
</entry>
<entry>
<para>
spinlock with test-test-and-swap on shared variable, adaptive retries
while busy waiting
</para>
</entry>
</row>
<row>
<entry>
<para>
BOOST_FIBERS_SPINLOCK_TTAS_FUTEX
</para>
</entry>
<entry>
<para>
-
</para>
</entry>
<entry>
<para>
spinlock with test-test-and-swap on shared variable, suspend on futex
after certain number of retries
</para>
</entry>
</row>
<row>
<entry>
<para>
BOOST_FIBERS_SPINLOCK_TTAS_ADAPTIVE_FUTEX
</para>
</entry>
<entry>
<para>
-
</para>
</entry>
<entry>
<para>
spinlock with test-test-and-swap on shared variable, while busy waiting
adaptive retries, suspend on futex certain amount of retries
</para>
</entry>
</row>
<row>
<entry>
<para>
BOOST_FIBERS_SPINLOCK_TTAS + BOOST_USE_TSX
</para>
</entry>
<entry>
<para>
-
</para>
</entry>
<entry>
<para>
spinlock with test-test-and-swap and speculative execution (Intel
TSX required)
</para>
</entry>
</row>
<row>
<entry>
<para>
BOOST_FIBERS_SPINLOCK_TTAS_ADAPTIVE + BOOST_USE_TSX
</para>
</entry>
<entry>
<para>
-
</para>
</entry>
<entry>
<para>
spinlock with test-test-and-swap on shared variable, adaptive retries
while busy waiting and speculative execution (Intel TSX required)
</para>
</entry>
</row>
<row>
<entry>
<para>
BOOST_FIBERS_SPINLOCK_TTAS_FUTEX + BOOST_USE_TSX
</para>
</entry>
<entry>
<para>
-
</para>
</entry>
<entry>
<para>
spinlock with test-test-and-swap on shared variable, suspend on futex
after certain number of retries and speculative execution (Intel
TSX required)
</para>
</entry>
</row>
<row>
<entry>
<para>
BOOST_FIBERS_SPINLOCK_TTAS_ADAPTIVE_FUTEX + BOOST_USE_TSX
</para>
</entry>
<entry>
<para>
-
</para>
</entry>
<entry>
<para>
spinlock with test-test-and-swap on shared variable, while busy waiting
adaptive retries, suspend on futex certain amount of retries and
speculative execution (Intel TSX required)
</para>
</entry>
</row>
<row>
<entry>
<para>
BOOST_FIBERS_SPIN_SINGLE_CORE
</para>
</entry>
<entry>
<para>
-
</para>
</entry>
<entry>
<para>
on single core machines with multiple threads, yield thread (<code><phrase
role="identifier">std</phrase><phrase role="special">::</phrase><phrase
role="identifier">this_thread</phrase><phrase role="special">::</phrase><phrase
role="identifier">yield</phrase><phrase role="special">()</phrase></code>)
after collisions
</para>
</entry>
</row>
<row>
<entry>
<para>
BOOST_FIBERS_RETRY_THRESHOLD
</para>
</entry>
<entry>
<para>
64
</para>
</entry>
<entry>
<para>
max number of retries while busy spinning, the use fallback
</para>
</entry>
</row>
<row>
<entry>
<para>
BOOST_FIBERS_CONTENTION_WINDOW_THRESHOLD
</para>
</entry>
<entry>
<para>
16
</para>
</entry>
<entry>
<para>
max size of collisions window, expressed as exponent for the basis
of two
</para>
</entry>
</row>
<row>
<entry>
<para>
BOOST_FIBERS_SPIN_BEFORE_SLEEP0
</para>
</entry>
<entry>
<para>
32
</para>
</entry>
<entry>
<para>
max number of retries that relax the processor before the thread
sleeps for 0s
</para>
</entry>
</row>
<row>
<entry>
<para>
BOOST_FIBERS_SPIN_BEFORE_YIELD
</para>
</entry>
<entry>
<para>
64
</para>
</entry>
<entry>
<para>
max number of retries where the thread sleeps for 0s before yield
thread (<code><phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase
role="identifier">this_thread</phrase><phrase role="special">::</phrase><phrase
role="identifier">yield</phrase><phrase role="special">()</phrase></code>)
</para>
</entry>
</row>
</tbody>
</tgroup>
</table>
</section>
<section id="fiber.custom">
<title><anchor id="custom"/><link linkend="fiber.custom">Customization</link></title>
<bridgehead renderas="sect3" id="fiber.custom.h0">
<phrase id="fiber.custom.overview"/><link linkend="fiber.custom.overview">Overview</link>
</bridgehead>
<para>
As noted in the <link linkend="scheduling">Scheduling</link> section, by default
<emphasis role="bold">Boost.Fiber</emphasis> uses its own <link linkend="class_round_robin"><code>round_robin</code></link> scheduler
for each thread. To control the way <emphasis role="bold">Boost.Fiber</emphasis>
schedules ready fibers on a particular thread, in general you must follow several
steps. This section discusses those steps, whereas <link linkend="scheduling">Scheduling</link>
serves as a reference for the classes involved.
</para>
<para>
The library's fiber manager keeps track of suspended (blocked) fibers. Only
when a fiber becomes ready to run is it passed to the scheduler. Of course,
if there are fewer than two ready fibers, the scheduler's job is trivial. Only
when there are two or more ready fibers does the particular scheduler implementation
start to influence the overall sequence of fiber execution.
</para>
<para>
In this section we illustrate a simple custom scheduler that honors an integer
fiber priority. We will implement it such that a fiber with higher priority
is preferred over a fiber with lower priority. Any fibers with equal priority
values are serviced on a round-robin basis.
</para>
<para>
The full source code for the examples below is found in <ulink url="../../examples/priority.cpp">priority.cpp</ulink>.
</para>
<bridgehead renderas="sect3" id="fiber.custom.h1">
<phrase id="fiber.custom.custom_property_class"/><link linkend="fiber.custom.custom_property_class">Custom
Property Class</link>
</bridgehead>
<para>
The first essential point is that we must associate an integer priority with
each fiber.<footnote id="fiber.custom.f0">
<para>
A previous version of the Fiber library implicitly tracked an int priority
for each fiber, even though the default scheduler ignored it. This has been
dropped, since the library now supports arbitrary scheduler-specific fiber
properties.
</para>
</footnote>
</para>
<para>
One might suggest deriving a custom <link linkend="class_fiber"><code>fiber</code></link> subclass to store such
properties. There are a couple of reasons for the present mechanism.
</para>
<orderedlist>
<listitem>
<simpara>
<emphasis role="bold">Boost.Fiber</emphasis> provides a number of different
ways to launch a fiber. (Consider <link linkend="fibers_async"><code>fibers::async()</code></link>.) Higher-level
libraries might introduce additional such wrapper functions. A custom scheduler
must associate its custom properties with <emphasis>every</emphasis> fiber
in the thread, not only the ones explicitly launched by instantiating a
custom <code><phrase role="identifier">fiber</phrase></code> subclass.
</simpara>
</listitem>
<listitem>
<simpara>
Consider a large existing program that launches fibers in many different
places in the code. We discover a need to introduce a custom scheduler
for a particular thread. If supporting that scheduler's custom properties
required a particular <code><phrase role="identifier">fiber</phrase></code>
subclass, we would have to hunt down and modify every place that launches
a fiber on that thread.
</simpara>
</listitem>
<listitem>
<simpara>
The <link linkend="class_fiber"><code>fiber</code></link> class is actually just a handle to internal <link linkend="class_context"><code>context</code></link> data.
A subclass of <code><phrase role="identifier">fiber</phrase></code> would
not add data to <code><phrase role="identifier">context</phrase></code>.
</simpara>
</listitem>
</orderedlist>
<para>
The present mechanism allows you to <quote>drop in</quote> a custom scheduler
with its attendant custom properties <emphasis>without</emphasis> altering
the rest of your application.
</para>
<para>
Instead of deriving a custom scheduler fiber properties subclass from <link linkend="class_fiber"><code>fiber</code></link>,
you must instead derive it from <link linkend="class_fiber_properties"><code>fiber_properties</code></link>.
</para>
<para>
<programlisting><phrase role="keyword">class</phrase> <phrase role="identifier">priority_props</phrase> <phrase role="special">:</phrase> <phrase role="keyword">public</phrase> <phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">fibers</phrase><phrase role="special">::</phrase><phrase role="identifier">fiber_properties</phrase> <phrase role="special">{</phrase>
<phrase role="keyword">public</phrase><phrase role="special">:</phrase>
<phrase role="identifier">priority_props</phrase><phrase role="special">(</phrase> <phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">fibers</phrase><phrase role="special">::</phrase><phrase role="identifier">context</phrase> <phrase role="special">*</phrase> <phrase role="identifier">ctx</phrase><phrase role="special">):</phrase>
<phrase role="identifier">fiber_properties</phrase><phrase role="special">(</phrase> <phrase role="identifier">ctx</phrase><phrase role="special">),</phrase> <co id="fiber.custom.c0" linkends="fiber.custom.c1" />
<phrase role="identifier">priority_</phrase><phrase role="special">(</phrase> <phrase role="number">0</phrase><phrase role="special">)</phrase> <phrase role="special">{</phrase>
<phrase role="special">}</phrase>
<phrase role="keyword">int</phrase> <phrase role="identifier">get_priority</phrase><phrase role="special">()</phrase> <phrase role="keyword">const</phrase> <phrase role="special">{</phrase>
<phrase role="keyword">return</phrase> <phrase role="identifier">priority_</phrase><phrase role="special">;</phrase> <co id="fiber.custom.c2" linkends="fiber.custom.c3" />
<phrase role="special">}</phrase>
<phrase role="comment">// Call this method to alter priority, because we must notify</phrase>
<phrase role="comment">// priority_scheduler of any change.</phrase>
<phrase role="keyword">void</phrase> <phrase role="identifier">set_priority</phrase><phrase role="special">(</phrase> <phrase role="keyword">int</phrase> <phrase role="identifier">p</phrase><phrase role="special">)</phrase> <phrase role="special">{</phrase> <co id="fiber.custom.c4" linkends="fiber.custom.c5" />
<phrase role="comment">// Of course, it's only worth reshuffling the queue and all if we're</phrase>
<phrase role="comment">// actually changing the priority.</phrase>
<phrase role="keyword">if</phrase> <phrase role="special">(</phrase> <phrase role="identifier">p</phrase> <phrase role="special">!=</phrase> <phrase role="identifier">priority_</phrase><phrase role="special">)</phrase> <phrase role="special">{</phrase>
<phrase role="identifier">priority_</phrase> <phrase role="special">=</phrase> <phrase role="identifier">p</phrase><phrase role="special">;</phrase>
<phrase role="identifier">notify</phrase><phrase role="special">();</phrase>
<phrase role="special">}</phrase>
<phrase role="special">}</phrase>
<phrase role="comment">// The fiber name of course is solely for purposes of this example</phrase>
<phrase role="comment">// program; it has nothing to do with implementing scheduler priority.</phrase>
<phrase role="comment">// This is a public data member -- not requiring set/get access methods --</phrase>
<phrase role="comment">// because we need not inform the scheduler of any change.</phrase>
<phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">string</phrase> <phrase role="identifier">name</phrase><phrase role="special">;</phrase> <co id="fiber.custom.c6" linkends="fiber.custom.c7" />
<phrase role="keyword">private</phrase><phrase role="special">:</phrase>
<phrase role="keyword">int</phrase> <phrase role="identifier">priority_</phrase><phrase role="special">;</phrase>
<phrase role="special">};</phrase>
</programlisting>
</para>
<calloutlist>
<callout arearefs="fiber.custom.c0" id="fiber.custom.c1">
<para>
Your subclass constructor must accept a <literal><link linkend="class_context"><code>context</code></link>*</literal>
and pass it to the <code><phrase role="identifier">fiber_properties</phrase></code>
constructor.
</para>
</callout>
<callout arearefs="fiber.custom.c2" id="fiber.custom.c3">
<para>
Provide read access methods at your own discretion.
</para>
</callout>
<callout arearefs="fiber.custom.c4" id="fiber.custom.c5">
<para>
It's important to call <code><phrase role="identifier">notify</phrase><phrase
role="special">()</phrase></code> on any change in a property that can
affect the scheduler's behavior. Therefore, such modifications should only
be performed through an access method.
</para>
</callout>
<callout arearefs="fiber.custom.c6" id="fiber.custom.c7">
<para>
A property that does not affect the scheduler does not need access methods.
</para>
</callout>
</calloutlist>
<bridgehead renderas="sect3" id="fiber.custom.h2">
<phrase id="fiber.custom.custom_scheduler_class"/><link linkend="fiber.custom.custom_scheduler_class">Custom
Scheduler Class</link>
</bridgehead>
<para>
Now we can derive a custom scheduler from <link linkend="class_algorithm_with_properties"><code>algorithm_with_properties&lt;&gt;</code></link>,
specifying our custom property class <code><phrase role="identifier">priority_props</phrase></code>
as the template parameter.
</para>
<para>
<programlisting><phrase role="keyword">class</phrase> <phrase role="identifier">priority_scheduler</phrase> <phrase role="special">:</phrase>
<phrase role="keyword">public</phrase> <phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">fibers</phrase><phrase role="special">::</phrase><phrase role="identifier">algo</phrase><phrase role="special">::</phrase><phrase role="identifier">algorithm_with_properties</phrase><phrase role="special">&lt;</phrase> <phrase role="identifier">priority_props</phrase> <phrase role="special">&gt;</phrase> <phrase role="special">{</phrase>
<phrase role="keyword">private</phrase><phrase role="special">:</phrase>
<phrase role="keyword">typedef</phrase> <phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">fibers</phrase><phrase role="special">::</phrase><phrase role="identifier">scheduler</phrase><phrase role="special">::</phrase><phrase role="identifier">ready_queue_type</phrase><co id="fiber.custom.c8" linkends="fiber.custom.c9" /> <phrase role="identifier">rqueue_t</phrase><phrase role="special">;</phrase>
<phrase role="identifier">rqueue_t</phrase> <phrase role="identifier">rqueue_</phrase><phrase role="special">;</phrase>
<phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">mutex</phrase> <phrase role="identifier">mtx_</phrase><phrase role="special">{};</phrase>
<phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">condition_variable</phrase> <phrase role="identifier">cnd_</phrase><phrase role="special">{};</phrase>
<phrase role="keyword">bool</phrase> <phrase role="identifier">flag_</phrase><phrase role="special">{</phrase> <phrase role="keyword">false</phrase> <phrase role="special">};</phrase>
<phrase role="keyword">public</phrase><phrase role="special">:</phrase>
<phrase role="identifier">priority_scheduler</phrase><phrase role="special">()</phrase> <phrase role="special">:</phrase>
<phrase role="identifier">rqueue_</phrase><phrase role="special">()</phrase> <phrase role="special">{</phrase>
<phrase role="special">}</phrase>
<phrase role="comment">// For a subclass of algorithm_with_properties&lt;&gt;, it's important to</phrase>
<phrase role="comment">// override the correct awakened() overload.</phrase>
<co id="fiber.custom.c10" linkends="fiber.custom.c11" /><phrase role="keyword">virtual</phrase> <phrase role="keyword">void</phrase> <phrase role="identifier">awakened</phrase><phrase role="special">(</phrase> <phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">fibers</phrase><phrase role="special">::</phrase><phrase role="identifier">context</phrase> <phrase role="special">*</phrase> <phrase role="identifier">ctx</phrase><phrase role="special">,</phrase> <phrase role="identifier">priority_props</phrase> <phrase role="special">&amp;</phrase> <phrase role="identifier">props</phrase><phrase role="special">)</phrase> <phrase role="keyword">noexcept</phrase> <phrase role="special">{</phrase>
<phrase role="keyword">int</phrase> <phrase role="identifier">ctx_priority</phrase> <phrase role="special">=</phrase> <phrase role="identifier">props</phrase><phrase role="special">.</phrase><phrase role="identifier">get_priority</phrase><phrase role="special">();</phrase> <co id="fiber.custom.c12" linkends="fiber.custom.c13" />
<phrase role="comment">// With this scheduler, fibers with higher priority values are</phrase>
<phrase role="comment">// preferred over fibers with lower priority values. But fibers with</phrase>
<phrase role="comment">// equal priority values are processed in round-robin fashion. So when</phrase>
<phrase role="comment">// we're handed a new context*, put it at the end of the fibers</phrase>
<phrase role="comment">// with that same priority. In other words: search for the first fiber</phrase>
<phrase role="comment">// in the queue with LOWER priority, and insert before that one.</phrase>
<phrase role="identifier">rqueue_t</phrase><phrase role="special">::</phrase><phrase role="identifier">iterator</phrase> <phrase role="identifier">i</phrase><phrase role="special">(</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">find_if</phrase><phrase role="special">(</phrase> <phrase role="identifier">rqueue_</phrase><phrase role="special">.</phrase><phrase role="identifier">begin</phrase><phrase role="special">(),</phrase> <phrase role="identifier">rqueue_</phrase><phrase role="special">.</phrase><phrase role="identifier">end</phrase><phrase role="special">(),</phrase>
<phrase role="special">[</phrase><phrase role="identifier">ctx_priority</phrase><phrase role="special">,</phrase><phrase role="keyword">this</phrase><phrase role="special">](</phrase> <phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">fibers</phrase><phrase role="special">::</phrase><phrase role="identifier">context</phrase> <phrase role="special">&amp;</phrase> <phrase role="identifier">c</phrase><phrase role="special">)</phrase>
<phrase role="special">{</phrase> <phrase role="keyword">return</phrase> <phrase role="identifier">properties</phrase><phrase role="special">(</phrase> <phrase role="special">&amp;</phrase><phrase role="identifier">c</phrase> <phrase role="special">).</phrase><phrase role="identifier">get_priority</phrase><phrase role="special">()</phrase> <phrase role="special">&lt;</phrase> <phrase role="identifier">ctx_priority</phrase><phrase role="special">;</phrase> <phrase role="special">}));</phrase>
<phrase role="comment">// Now, whether or not we found a fiber with lower priority,</phrase>
<phrase role="comment">// insert this new fiber here.</phrase>
<phrase role="identifier">rqueue_</phrase><phrase role="special">.</phrase><phrase role="identifier">insert</phrase><phrase role="special">(</phrase> <phrase role="identifier">i</phrase><phrase role="special">,</phrase> <phrase role="special">*</phrase> <phrase role="identifier">ctx</phrase><phrase role="special">);</phrase>
<phrase role="special">}</phrase>
<co id="fiber.custom.c14" linkends="fiber.custom.c15" /><phrase role="keyword">virtual</phrase> <phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">fibers</phrase><phrase role="special">::</phrase><phrase role="identifier">context</phrase> <phrase role="special">*</phrase> <phrase role="identifier">pick_next</phrase><phrase role="special">()</phrase> <phrase role="keyword">noexcept</phrase> <phrase role="special">{</phrase>
<phrase role="comment">// if ready queue is empty, just tell caller</phrase>
<phrase role="keyword">if</phrase> <phrase role="special">(</phrase> <phrase role="identifier">rqueue_</phrase><phrase role="special">.</phrase><phrase role="identifier">empty</phrase><phrase role="special">()</phrase> <phrase role="special">)</phrase> <phrase role="special">{</phrase>
<phrase role="keyword">return</phrase> <phrase role="keyword">nullptr</phrase><phrase role="special">;</phrase>
<phrase role="special">}</phrase>
<phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">fibers</phrase><phrase role="special">::</phrase><phrase role="identifier">context</phrase> <phrase role="special">*</phrase> <phrase role="identifier">ctx</phrase><phrase role="special">(</phrase> <phrase role="special">&amp;</phrase> <phrase role="identifier">rqueue_</phrase><phrase role="special">.</phrase><phrase role="identifier">front</phrase><phrase role="special">()</phrase> <phrase role="special">);</phrase>
<phrase role="identifier">rqueue_</phrase><phrase role="special">.</phrase><phrase role="identifier">pop_front</phrase><phrase role="special">();</phrase>
<phrase role="keyword">return</phrase> <phrase role="identifier">ctx</phrase><phrase role="special">;</phrase>
<phrase role="special">}</phrase>
<co id="fiber.custom.c16" linkends="fiber.custom.c17" /><phrase role="keyword">virtual</phrase> <phrase role="keyword">bool</phrase> <phrase role="identifier">has_ready_fibers</phrase><phrase role="special">()</phrase> <phrase role="keyword">const</phrase> <phrase role="keyword">noexcept</phrase> <phrase role="special">{</phrase>
<phrase role="keyword">return</phrase> <phrase role="special">!</phrase> <phrase role="identifier">rqueue_</phrase><phrase role="special">.</phrase><phrase role="identifier">empty</phrase><phrase role="special">();</phrase>
<phrase role="special">}</phrase>
<co id="fiber.custom.c18" linkends="fiber.custom.c19" /><phrase role="keyword">virtual</phrase> <phrase role="keyword">void</phrase> <phrase role="identifier">property_change</phrase><phrase role="special">(</phrase> <phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">fibers</phrase><phrase role="special">::</phrase><phrase role="identifier">context</phrase> <phrase role="special">*</phrase> <phrase role="identifier">ctx</phrase><phrase role="special">,</phrase> <phrase role="identifier">priority_props</phrase> <phrase role="special">&amp;</phrase> <phrase role="identifier">props</phrase><phrase role="special">)</phrase> <phrase role="keyword">noexcept</phrase> <phrase role="special">{</phrase>
<phrase role="comment">// Although our priority_props class defines multiple properties, only</phrase>
<phrase role="comment">// one of them (priority) actually calls notify() when changed. The</phrase>
<phrase role="comment">// point of a property_change() override is to reshuffle the ready</phrase>
<phrase role="comment">// queue according to the updated priority value.</phrase>
<phrase role="comment">// 'ctx' might not be in our queue at all, if caller is changing the</phrase>
<phrase role="comment">// priority of (say) the running fiber. If it's not there, no need to</phrase>
<phrase role="comment">// move it: we'll handle it next time it hits awakened().</phrase>
<phrase role="keyword">if</phrase> <phrase role="special">(</phrase> <phrase role="special">!</phrase> <phrase role="identifier">ctx</phrase><phrase role="special">-&gt;</phrase><phrase role="identifier">ready_is_linked</phrase><phrase role="special">())</phrase> <phrase role="special">{</phrase> <co id="fiber.custom.c20" linkends="fiber.custom.c21" />
<phrase role="keyword">return</phrase><phrase role="special">;</phrase>
<phrase role="special">}</phrase>
<phrase role="comment">// Found ctx: unlink it</phrase>
<phrase role="identifier">ctx</phrase><phrase role="special">-&gt;</phrase><phrase role="identifier">ready_unlink</phrase><phrase role="special">();</phrase>
<phrase role="comment">// Here we know that ctx was in our ready queue, but we've unlinked</phrase>
<phrase role="comment">// it. We happen to have a method that will (re-)add a context* to the</phrase>
<phrase role="comment">// right place in the ready queue.</phrase>
<phrase role="identifier">awakened</phrase><phrase role="special">(</phrase> <phrase role="identifier">ctx</phrase><phrase role="special">,</phrase> <phrase role="identifier">props</phrase><phrase role="special">);</phrase>
<phrase role="special">}</phrase>
<phrase role="keyword">void</phrase> <phrase role="identifier">suspend_until</phrase><phrase role="special">(</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">chrono</phrase><phrase role="special">::</phrase><phrase role="identifier">steady_clock</phrase><phrase role="special">::</phrase><phrase role="identifier">time_point</phrase> <phrase role="keyword">const</phrase><phrase role="special">&amp;</phrase> <phrase role="identifier">time_point</phrase><phrase role="special">)</phrase> <phrase role="keyword">noexcept</phrase> <phrase role="special">{</phrase>
<phrase role="keyword">if</phrase> <phrase role="special">(</phrase> <phrase role="special">(</phrase><phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">chrono</phrase><phrase role="special">::</phrase><phrase role="identifier">steady_clock</phrase><phrase role="special">::</phrase><phrase role="identifier">time_point</phrase><phrase role="special">::</phrase><phrase role="identifier">max</phrase><phrase role="special">)()</phrase> <phrase role="special">==</phrase> <phrase role="identifier">time_point</phrase><phrase role="special">)</phrase> <phrase role="special">{</phrase>
<phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">unique_lock</phrase><phrase role="special">&lt;</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">mutex</phrase> <phrase role="special">&gt;</phrase> <phrase role="identifier">lk</phrase><phrase role="special">(</phrase> <phrase role="identifier">mtx_</phrase><phrase role="special">);</phrase>
<phrase role="identifier">cnd_</phrase><phrase role="special">.</phrase><phrase role="identifier">wait</phrase><phrase role="special">(</phrase> <phrase role="identifier">lk</phrase><phrase role="special">,</phrase> <phrase role="special">[</phrase><phrase role="keyword">this</phrase><phrase role="special">](){</phrase> <phrase role="keyword">return</phrase> <phrase role="identifier">flag_</phrase><phrase role="special">;</phrase> <phrase role="special">});</phrase>
<phrase role="identifier">flag_</phrase> <phrase role="special">=</phrase> <phrase role="keyword">false</phrase><phrase role="special">;</phrase>
<phrase role="special">}</phrase> <phrase role="keyword">else</phrase> <phrase role="special">{</phrase>
<phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">unique_lock</phrase><phrase role="special">&lt;</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">mutex</phrase> <phrase role="special">&gt;</phrase> <phrase role="identifier">lk</phrase><phrase role="special">(</phrase> <phrase role="identifier">mtx_</phrase><phrase role="special">);</phrase>
<phrase role="identifier">cnd_</phrase><phrase role="special">.</phrase><phrase role="identifier">wait_until</phrase><phrase role="special">(</phrase> <phrase role="identifier">lk</phrase><phrase role="special">,</phrase> <phrase role="identifier">time_point</phrase><phrase role="special">,</phrase> <phrase role="special">[</phrase><phrase role="keyword">this</phrase><phrase role="special">](){</phrase> <phrase role="keyword">return</phrase> <phrase role="identifier">flag_</phrase><phrase role="special">;</phrase> <phrase role="special">});</phrase>
<phrase role="identifier">flag_</phrase> <phrase role="special">=</phrase> <phrase role="keyword">false</phrase><phrase role="special">;</phrase>
<phrase role="special">}</phrase>
<phrase role="special">}</phrase>
<phrase role="keyword">void</phrase> <phrase role="identifier">notify</phrase><phrase role="special">()</phrase> <phrase role="keyword">noexcept</phrase> <phrase role="special">{</phrase>
<phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">unique_lock</phrase><phrase role="special">&lt;</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">mutex</phrase> <phrase role="special">&gt;</phrase> <phrase role="identifier">lk</phrase><phrase role="special">(</phrase> <phrase role="identifier">mtx_</phrase><phrase role="special">);</phrase>
<phrase role="identifier">flag_</phrase> <phrase role="special">=</phrase> <phrase role="keyword">true</phrase><phrase role="special">;</phrase>
<phrase role="identifier">lk</phrase><phrase role="special">.</phrase><phrase role="identifier">unlock</phrase><phrase role="special">();</phrase>
<phrase role="identifier">cnd_</phrase><phrase role="special">.</phrase><phrase role="identifier">notify_all</phrase><phrase role="special">();</phrase>
<phrase role="special">}</phrase>
<phrase role="special">};</phrase>
</programlisting>
</para>
<calloutlist>
<callout arearefs="fiber.custom.c8" id="fiber.custom.c9">
<para>
See <link linkend="ready_queue_t">ready_queue_t</link>.
</para>
</callout>
<callout arearefs="fiber.custom.c10" id="fiber.custom.c11">
<para>
You must override the <link linkend="algorithm_with_properties_awakened"><code>algorithm_with_properties::awakened()</code></link>
method.
This is how your scheduler receives notification of a fiber that has become
ready to run.
</para>
</callout>
<callout arearefs="fiber.custom.c12" id="fiber.custom.c13">
<para>
<code><phrase role="identifier">props</phrase></code> is the instance of
priority_props associated with the passed fiber <code><phrase role="identifier">ctx</phrase></code>.
</para>
</callout>
<callout arearefs="fiber.custom.c14" id="fiber.custom.c15">
<para>
You must override the <link linkend="algorithm_with_properties_pick_next"><code>algorithm_with_properties::pick_next()</code></link>
method.
This is how your scheduler actually advises the fiber manager of the next
fiber to run.
</para>
</callout>
<callout arearefs="fiber.custom.c16" id="fiber.custom.c17">
<para>
You must override <link linkend="algorithm_with_properties_has_ready_fibers"><code>algorithm_with_properties::has_ready_fibers()</code></link>
to
inform the fiber manager of the state of your ready queue.
</para>
</callout>
<callout arearefs="fiber.custom.c18" id="fiber.custom.c19">
<para>
Overriding <link linkend="algorithm_with_properties_property_change"><code>algorithm_with_properties::property_change()</code></link>
is
optional. This override handles the case in which the running fiber changes
the priority of another ready fiber: a fiber already in our queue. In that
case, move the updated fiber within the queue.
</para>
</callout>
<callout arearefs="fiber.custom.c20" id="fiber.custom.c21">
<para>
Your <code><phrase role="identifier">property_change</phrase><phrase role="special">()</phrase></code>
override must be able to handle the case in which the passed <code><phrase
role="identifier">ctx</phrase></code> is not in your ready queue. It might
be running, or it might be blocked.
</para>
</callout>
</calloutlist>
<para>
Our example <code><phrase role="identifier">priority_scheduler</phrase></code>
doesn't override <link linkend="algorithm_with_properties_new_properties"><code>algorithm_with_properties::new_properties()</code></link>:
we're content with allocating <code><phrase role="identifier">priority_props</phrase></code>
instances on the heap.
</para>
<bridgehead renderas="sect3" id="fiber.custom.h3">
<phrase id="fiber.custom.replace_default_scheduler"/><link linkend="fiber.custom.replace_default_scheduler">Replace
Default Scheduler</link>
</bridgehead>
<para>
You must call <link linkend="use_scheduling_algorithm"><code>use_scheduling_algorithm()</code></link> at the start
of each thread on which you want <emphasis role="bold">Boost.Fiber</emphasis>
to use your custom scheduler rather than its own default <link linkend="class_round_robin"><code>round_robin</code></link>.
Specifically, you must call <code><phrase role="identifier">use_scheduling_algorithm</phrase><phrase
role="special">()</phrase></code> before performing any other <emphasis role="bold">Boost.Fiber</emphasis>
operations on that thread.
</para>
<para>
<programlisting><phrase role="keyword">int</phrase> <phrase role="identifier">main</phrase><phrase role="special">(</phrase> <phrase role="keyword">int</phrase> <phrase role="identifier">argc</phrase><phrase role="special">,</phrase> <phrase role="keyword">char</phrase> <phrase role="special">*</phrase><phrase role="identifier">argv</phrase><phrase role="special">[])</phrase> <phrase role="special">{</phrase>
<phrase role="comment">// make sure we use our priority_scheduler rather than default round_robin</phrase>
<phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">fibers</phrase><phrase role="special">::</phrase><phrase role="identifier">use_scheduling_algorithm</phrase><phrase role="special">&lt;</phrase> <phrase role="identifier">priority_scheduler</phrase> <phrase role="special">&gt;();</phrase>
<phrase role="special">...</phrase>
<phrase role="special">}</phrase>
</programlisting>
</para>
<bridgehead renderas="sect3" id="fiber.custom.h4">
<phrase id="fiber.custom.use_properties"/><link linkend="fiber.custom.use_properties">Use
Properties</link>
</bridgehead>
<para>
The running fiber can access its own <link linkend="class_fiber_properties"><code>fiber_properties</code></link> subclass
instance by calling <link linkend="this_fiber_properties"><code>this_fiber::properties()</code></link>. Although
<code><phrase role="identifier">properties</phrase><phrase role="special">&lt;&gt;()</phrase></code>
is a nullary function, you must pass, as a template parameter, the <code><phrase
role="identifier">fiber_properties</phrase></code> subclass.
</para>
<para>
<programlisting><phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">this_fiber</phrase><phrase role="special">::</phrase><phrase role="identifier">properties</phrase><phrase role="special">&lt;</phrase> <phrase role="identifier">priority_props</phrase> <phrase role="special">&gt;().</phrase><phrase role="identifier">name</phrase> <phrase role="special">=</phrase> <phrase role="string">&quot;main&quot;</phrase><phrase role="special">;</phrase>
</programlisting>
</para>
<para>
Given a <link linkend="class_fiber"><code>fiber</code></link> instance still connected with a running fiber (that
is, not <link linkend="fiber_detach"><code>fiber::detach()</code></link>ed), you may access that fiber's properties
using <link linkend="fiber_properties"><code>fiber::properties()</code></link>. As with <code><phrase role="identifier">boost</phrase><phrase
role="special">::</phrase><phrase role="identifier">this_fiber</phrase><phrase
role="special">::</phrase><phrase role="identifier">properties</phrase><phrase
role="special">&lt;&gt;()</phrase></code>, you must pass your <code><phrase
role="identifier">fiber_properties</phrase></code> subclass as the template
parameter.
</para>
<para>
<programlisting><phrase role="keyword">template</phrase><phrase role="special">&lt;</phrase> <phrase role="keyword">typename</phrase> <phrase role="identifier">Fn</phrase> <phrase role="special">&gt;</phrase>
<phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">fibers</phrase><phrase role="special">::</phrase><phrase role="identifier">fiber</phrase> <phrase role="identifier">launch</phrase><phrase role="special">(</phrase> <phrase role="identifier">Fn</phrase> <phrase role="special">&amp;&amp;</phrase> <phrase role="identifier">func</phrase><phrase role="special">,</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">string</phrase> <phrase role="keyword">const</phrase><phrase role="special">&amp;</phrase> <phrase role="identifier">name</phrase><phrase role="special">,</phrase> <phrase role="keyword">int</phrase> <phrase role="identifier">priority</phrase><phrase role="special">)</phrase> <phrase role="special">{</phrase>
<phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">fibers</phrase><phrase role="special">::</phrase><phrase role="identifier">fiber</phrase> <phrase role="identifier">fiber</phrase><phrase role="special">(</phrase> <phrase role="identifier">func</phrase><phrase role="special">);</phrase>
<phrase role="identifier">priority_props</phrase> <phrase role="special">&amp;</phrase> <phrase role="identifier">props</phrase><phrase role="special">(</phrase> <phrase role="identifier">fiber</phrase><phrase role="special">.</phrase><phrase role="identifier">properties</phrase><phrase role="special">&lt;</phrase> <phrase role="identifier">priority_props</phrase> <phrase role="special">&gt;()</phrase> <phrase role="special">);</phrase>
<phrase role="identifier">props</phrase><phrase role="special">.</phrase><phrase role="identifier">name</phrase> <phrase role="special">=</phrase> <phrase role="identifier">name</phrase><phrase role="special">;</phrase>
<phrase role="identifier">props</phrase><phrase role="special">.</phrase><phrase role="identifier">set_priority</phrase><phrase role="special">(</phrase> <phrase role="identifier">priority</phrase><phrase role="special">);</phrase>
<phrase role="keyword">return</phrase> <phrase role="identifier">fiber</phrase><phrase role="special">;</phrase>
<phrase role="special">}</phrase>
</programlisting>
</para>
<para>
Launching a new fiber schedules that fiber as ready, but does <emphasis>not</emphasis>
immediately enter its <emphasis>fiber-function</emphasis>. The current fiber
retains control until it blocks (or yields, or terminates) for some other reason.
As shown in the <code><phrase role="identifier">launch</phrase><phrase role="special">()</phrase></code>
function above, it is reasonable to launch a fiber and immediately set relevant
properties -- such as, for instance, its priority. Your custom scheduler can
then make use of this information next time the fiber manager calls <link linkend="algorithm_with_properties_pick_next"><code>algorithm_with_properties::pick_next()</code></link>.
</para>
</section>
<section id="fiber.rationale">
<title><link linkend="fiber.rationale">Rationale</link></title>
<bridgehead renderas="sect3" id="fiber.rationale.h0">
<phrase id="fiber.rationale.preprocessor_defines"/><link linkend="fiber.rationale.preprocessor_defines">preprocessor
defines</link>
</bridgehead>
<table frame="all" id="fiber.rationale.preopcessor_defines">
<title>preopcessor defines</title>
<tgroup cols="2">
<thead>
<row>
<entry>
</entry>
<entry>
</entry>
</row>
</thead>
<tbody>
<row>
<entry>
<para>
BOOST_FIBERS_NO_ATOMICS
</para>
</entry>
<entry>
<para>
no <code><phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase
role="identifier">atomic</phrase><phrase role="special">&lt;&gt;</phrase></code>
used, inter-thread synchronization disabled
</para>
</entry>
</row>
<row>
<entry>
<para>
BOOST_FIBERS_SPINLOCK_STD_MUTEX
</para>
</entry>
<entry>
<para>
use <code><phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase
role="identifier">mutex</phrase></code> as spinlock instead of default
<code><phrase role="identifier">XCHG</phrase></code>-sinlock with
backoff
</para>
</entry>
</row>
<row>
<entry>
<para>
BOOST_FIBERS_SPIN_BACKOFF
</para>
</entry>
<entry>
<para>
limit determines when to used <code><phrase role="identifier">std</phrase><phrase
role="special">::</phrase><phrase role="identifier">this_thread</phrase><phrase
role="special">::</phrase><phrase role="identifier">yield</phrase><phrase
role="special">()</phrase></code> instead of mnemonic <code><phrase
role="identifier">pause</phrase><phrase role="special">/</phrase><phrase
role="identifier">yield</phrase></code> during busy wait (apllies
on to <code><phrase role="identifier">XCHG</phrase></code>-spinlock)
</para>
</entry>
</row>
<row>
<entry>
<para>
BOOST_FIBERS_SINGLE_CORE
</para>
</entry>
<entry>
<para>
allways call <code><phrase role="identifier">std</phrase><phrase
role="special">::</phrase><phrase role="identifier">this_thread</phrase><phrase
role="special">::</phrase><phrase role="identifier">yield</phrase><phrase
role="special">()</phrase></code> without backoff during busy wait
(apllies on to <code><phrase role="identifier">XCHG</phrase></code>-spinlock)
</para>
</entry>
</row>
</tbody>
</tgroup>
</table>
<bridgehead renderas="sect3" id="fiber.rationale.h1">
<phrase id="fiber.rationale.distinction_between_coroutines_and_fibers"/><link
linkend="fiber.rationale.distinction_between_coroutines_and_fibers">distinction
between coroutines and fibers</link>
</bridgehead>
<para>
The fiber library extends the coroutine library by adding a scheduler and synchronization
mechanisms.
</para>
<itemizedlist>
<listitem>
<simpara>
a coroutine yields
</simpara>
</listitem>
<listitem>
<simpara>
a fiber blocks
</simpara>
</listitem>
</itemizedlist>
<para>
When a coroutine yields, it passes control directly to its caller (or, in the
case of symmetric coroutines, a designated other coroutine). When a fiber blocks,
it implicitly passes control to the fiber scheduler. Coroutines have no scheduler
because they need no scheduler.<footnote id="fiber.rationale.f0">
<para>
<ulink url="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2014/n4024.pdf">'N4024:
Distinguishing coroutines and fibers'</ulink>
</para>
</footnote>.
</para>
<bridgehead renderas="sect3" id="fiber.rationale.h2">
<phrase id="fiber.rationale.what_about_transactional_memory"/><link linkend="fiber.rationale.what_about_transactional_memory">what
about transactional memory</link>
</bridgehead>
<para>
GCC supports transactional memory since version 4.7. Unfortunately tests show
that transactional memory is slower (ca. 4x) than spinlocks using atomics.
Once transactional memory is improved (supporting hybrid tm), spinlocks will
be replaced by __transaction_atomic{} statements surrounding the critical sections.
</para>
<bridgehead renderas="sect3" id="fiber.rationale.h3">
<phrase id="fiber.rationale.synchronization_between_fibers_running_in_different_threads"/><link
linkend="fiber.rationale.synchronization_between_fibers_running_in_different_threads">synchronization
between fibers running in different threads</link>
</bridgehead>
<para>
Synchronization classes from <ulink url="http://www.boost.org/doc/libs/release/libs/thread/index.html">Boost.Thread</ulink>
block the entire thread. In contrast, the synchronization classes from <emphasis
role="bold">Boost.Fiber</emphasis> block only specific fibers, so that the
scheduler can still keep the thread busy running other fibers in the meantime.
The synchronization classes from <emphasis role="bold">Boost.Fiber</emphasis>
are designed to be thread-safe, i.e. it is possible to synchronize fibers running
in different threads as well as fibers running in the same thread. (However,
there is a build option to disable cross-thread fiber synchronization support;
see <link linkend="cross_thread_sync">this description</link>.)
</para>
<anchor id="spurious_wakeup"/>
<bridgehead renderas="sect3" id="fiber.rationale.h4">
<phrase id="fiber.rationale.spurious_wakeup"/><link linkend="fiber.rationale.spurious_wakeup">spurious
wakeup</link>
</bridgehead>
<para>
Spurious wakeup can happen when using <ulink url="http://en.cppreference.com/w/cpp/thread/condition_variable"><code><phrase
role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">condition_variable</phrase></code></ulink>:
the condition variable appears to be have been signaled while the awaited condition
may still be false. Spurious wakeup can happen repeatedly and is caused on
some multiprocessor systems where making <code><phrase role="identifier">std</phrase><phrase
role="special">::</phrase><phrase role="identifier">condition_variable</phrase></code>
wakeup completely predictable would slow down all <code><phrase role="identifier">std</phrase><phrase
role="special">::</phrase><phrase role="identifier">condition_variable</phrase></code>
operations.<footnote id="fiber.rationale.f1">
<para>
David R. Butenhof <quote>Programming with POSIX Threads</quote>
</para>
</footnote>
</para>
<para>
<link linkend="class_condition_variable"><code>condition_variable</code></link> is not subject to spurious wakeup.
Nonetheless it is prudent to test the business-logic condition in a <code><phrase
role="identifier">wait</phrase><phrase role="special">()</phrase></code> loop
&mdash; or, equivalently, use one of the <code><phrase role="identifier">wait</phrase><phrase
role="special">(</phrase> <phrase role="identifier">lock</phrase><phrase role="special">,</phrase>
<phrase role="identifier">predicate</phrase> <phrase role="special">)</phrase></code>
overloads.
</para>
<para>
See also <link linkend="condition_variable_spurious_wakeups">No Spurious Wakeups</link>.
</para>
<bridgehead renderas="sect3" id="fiber.rationale.h5">
<phrase id="fiber.rationale.migrating_fibers_between_threads"/><link linkend="fiber.rationale.migrating_fibers_between_threads">migrating
fibers between threads</link>
</bridgehead>
<para>
Support for migrating fibers between threads has been integrated. The user-defined
scheduler must call <link linkend="context_detach"><code>context::detach()</code></link> on a fiber-context on the
source thread and <link linkend="context_attach"><code>context::attach()</code></link> on the destination thread,
passing the fiber-context to migrate. (For more information about custom schedulers,
see <link linkend="custom">Customization</link>.) Examples <code><phrase role="identifier">work_sharing</phrase></code>
and <code><phrase role="identifier">work_stealing</phrase></code> in directory
<code><phrase role="identifier">examples</phrase></code> might be used as a
blueprint.
</para>
<para>
See also <link linkend="migration">Migrating fibers between threads</link>.
</para>
<bridgehead renderas="sect3" id="fiber.rationale.h6">
<phrase id="fiber.rationale.support_for_boost_asio"/><link linkend="fiber.rationale.support_for_boost_asio">support
for Boost.Asio</link>
</bridgehead>
<para>
Support for <ulink url="http://www.boost.org/doc/libs/release/libs/asio/index.html">Boost.Asio</ulink>&#8217;s
<emphasis>async-result</emphasis> is not part of the official API. However,
to integrate with a <ulink url="http://www.boost.org/doc/libs/release/doc/html/boost_asio/reference/io_service.html"><code><phrase
role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">asio</phrase><phrase
role="special">::</phrase><phrase role="identifier">io_service</phrase></code></ulink>,
see <link linkend="integration">Sharing a Thread with Another Main Loop</link>.
To interface smoothly with an arbitrary Asio async I/O operation, see <link
linkend="callbacks_asio">Then There&#8217;s <ulink url="http://www.boost.org/doc/libs/release/libs/asio/index.html">Boost.Asio</ulink></link>.
</para>
<bridgehead renderas="sect3" id="fiber.rationale.h7">
<phrase id="fiber.rationale.tested_compilers"/><link linkend="fiber.rationale.tested_compilers">tested
compilers</link>
</bridgehead>
<para>
The library was tested with GCC-5.1.1, Clang-3.6.0 and MSVC-14.0 in c++11-mode.
</para>
<bridgehead renderas="sect3" id="fiber.rationale.h8">
<phrase id="fiber.rationale.supported_architectures"/><link linkend="fiber.rationale.supported_architectures">supported
architectures</link>
</bridgehead>
<para>
<emphasis role="bold">Boost.Fiber</emphasis> depends on <ulink url="http://www.boost.org/doc/libs/release/libs/context/index.html">Boost.Context</ulink>
- the list of supported architectures can be found <ulink url="http://www.boost.org/doc/libs/release/libs/context/doc/html/context/architectures.html">here</ulink>.
</para>
</section>
<section id="fiber.acknowledgements">
<title><link linkend="fiber.acknowledgements">Acknowledgments</link></title>
<para>
I'd like to thank Agustín Bergé, Eugene Yakubovich, Giovanni Piero Deretta
and especially Nat Goodspeed.
</para>
</section>
</library>