16750 lines
1.2 MiB
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"><</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">></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 — 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<></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 "C"
|
|
never throw a C++ exception) to /EHs (tells compiler assumes that functions
|
|
declared as extern "C" 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"><</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">></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"><(</phrase> <phrase role="identifier">fiber</phrase> <phrase role="keyword">const</phrase><phrase role="special">&</phrase> <phrase role="identifier">l</phrase><phrase role="special">,</phrase> <phrase role="identifier">fiber</phrase> <phrase role="keyword">const</phrase><phrase role="special">&</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">&</phrase> <phrase role="identifier">l</phrase><phrase role="special">,</phrase> <phrase role="identifier">fiber</phrase> <phrase role="special">&</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"><</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">></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">&&</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"><</phrase> <phrase role="keyword">typename</phrase> <phrase role="identifier">PROPS</phrase> <phrase role="special">></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"><</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">></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"><</phrase> <phrase role="identifier">Clock</phrase><phrase role="special">,</phrase> <phrase role="identifier">Duration</phrase> <phrase role="special">></phrase> <phrase role="keyword">const</phrase><phrase role="special">&</phrase> <phrase role="identifier">abs_time</phrase><phrase role="special">)</phrase>
|
|
<phrase role="keyword">template</phrase><phrase role="special"><</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">></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"><</phrase> <phrase role="identifier">Rep</phrase><phrase role="special">,</phrase> <phrase role="identifier">Period</phrase> <phrase role="special">></phrase> <phrase role="keyword">const</phrase><phrase role="special">&</phrase> <phrase role="identifier">rel_time</phrase><phrase role="special">);</phrase>
|
|
<phrase role="keyword">template</phrase><phrase role="special"><</phrase> <phrase role="keyword">typename</phrase> <phrase role="identifier">PROPS</phrase> <phrase role="special">></phrase>
|
|
<phrase role="identifier">PROPS</phrase> <phrase role="special">&</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<></code></link> or
|
|
<link linkend="class_packaged_task"><code>packaged_task<></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’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"><</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">></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"><</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">></phrase>
|
|
<phrase role="identifier">fiber</phrase><phrase role="special">(</phrase> <phrase role="identifier">Fn</phrase> <phrase role="special">&&,</phrase> <phrase role="identifier">Args</phrase> <phrase role="special">&&</phrase> <phrase role="special">...);</phrase>
|
|
|
|
<phrase role="keyword">template</phrase><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">></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">&&,</phrase> <phrase role="identifier">Args</phrase> <phrase role="special">&&</phrase> <phrase role="special">...);</phrase>
|
|
|
|
<phrase role="keyword">template</phrase><phrase role="special"><</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">></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">&&,</phrase> <phrase role="identifier">Fn</phrase> <phrase role="special">&&,</phrase> <phrase role="identifier">Args</phrase> <phrase role="special">&&</phrase> <phrase role="special">...);</phrase>
|
|
|
|
<phrase role="keyword">template</phrase><phrase role="special"><</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">></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">&&,</phrase> <phrase role="identifier">Fn</phrase> <phrase role="special">&&,</phrase> <phrase role="identifier">Args</phrase> <phrase role="special">&&</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">&)</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="keyword">operator</phrase><phrase role="special">=(</phrase> <phrase role="identifier">fiber</phrase> <phrase role="keyword">const</phrase><phrase role="special">&)</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">&&)</phrase> <phrase role="keyword">noexcept</phrase><phrase role="special">;</phrase>
|
|
|
|
<phrase role="identifier">fiber</phrase> <phrase role="special">&</phrase> <phrase role="keyword">operator</phrase><phrase role="special">=(</phrase> <phrase role="identifier">fiber</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">&)</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"><</phrase> <phrase role="keyword">typename</phrase> <phrase role="identifier">PROPS</phrase> <phrase role="special">></phrase>
|
|
<phrase role="identifier">PROPS</phrase> <phrase role="special">&</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"><(</phrase> <phrase role="identifier">fiber</phrase> <phrase role="keyword">const</phrase><phrase role="special">&,</phrase> <phrase role="identifier">fiber</phrase> <phrase role="keyword">const</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">&,</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"><</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">></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">&&</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">-></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"><</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">></phrase>
|
|
<phrase role="identifier">fiber</phrase><phrase role="special">(</phrase> <phrase role="identifier">Fn</phrase> <phrase role="special">&&</phrase> <phrase role="identifier">fn</phrase><phrase role="special">,</phrase> <phrase role="identifier">Args</phrase> <phrase role="special">&&</phrase> <phrase role="special">...</phrase> <phrase role="identifier">args</phrase><phrase role="special">);</phrase>
|
|
|
|
<phrase role="keyword">template</phrase><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">></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">&&</phrase> <phrase role="identifier">fn</phrase><phrase role="special">,</phrase> <phrase role="identifier">Args</phrase> <phrase role="special">&&</phrase> <phrase role="special">...</phrase> <phrase role="identifier">args</phrase><phrase role="special">);</phrase>
|
|
|
|
<phrase role="keyword">template</phrase><phrase role="special"><</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">></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">&&</phrase> <phrase role="identifier">salloc</phrase><phrase role="special">,</phrase> <phrase role="identifier">Fn</phrase> <phrase role="special">&&</phrase> <phrase role="identifier">fn</phrase><phrase role="special">,</phrase> <phrase role="identifier">Args</phrase> <phrase role="special">&&</phrase> <phrase role="special">...</phrase> <phrase role="identifier">args</phrase><phrase role="special">);</phrase>
|
|
|
|
<phrase role="keyword">template</phrase><phrase role="special"><</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">></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">&&</phrase> <phrase role="identifier">salloc</phrase><phrase role="special">,</phrase>
|
|
<phrase role="identifier">Fn</phrase> <phrase role="special">&&</phrase> <phrase role="identifier">fn</phrase><phrase role="special">,</phrase> <phrase role="identifier">Args</phrase> <phrase role="special">&&</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">&&</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">&</phrase> <phrase role="keyword">operator</phrase><phrase role="special">=(</phrase> <phrase role="identifier">fiber</phrase> <phrase role="special">&&</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">-></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">-></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"><</phrase> <phrase role="keyword">typename</phrase> <phrase role="identifier">PROPS</phrase> <phrase role="special">></phrase>
|
|
<phrase role="identifier">PROPS</phrase> <phrase role="special">&</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<></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<></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">&</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">-></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">-></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">&</phrase> <phrase role="identifier">l</phrase><phrase role="special">,</phrase> <phrase role="identifier">fiber</phrase> <phrase role="special">&</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<_bridgehead">
|
|
<phrase id="operator<"/>
|
|
<link linkend="operator<">Non-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">fiber</phrase> <phrase role="keyword">const</phrase><phrase role="special">&</phrase> <phrase role="identifier">l</phrase><phrase role="special">,</phrase> <phrase role="identifier">fiber</phrase> <phrase role="keyword">const</phrase><phrase role="special">&</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"><</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"><</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">></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">&&</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"><</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">></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">&)</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">&)</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">&)</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">&)</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">&)</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">&)</phrase> <phrase role="keyword">const</phrase> <phrase role="keyword">noexcept</phrase><phrase role="special">;</phrase>
|
|
|
|
<phrase role="keyword">template</phrase><phrase role="special"><</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">></phrase>
|
|
<phrase role="keyword">friend</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">basic_ostream</phrase><phrase role="special"><</phrase> <phrase role="identifier">charT</phrase><phrase role="special">,</phrase> <phrase role="identifier">traitsT</phrase> <phrase role="special">></phrase> <phrase role="special">&</phrase>
|
|
<phrase role="keyword">operator</phrase><phrase role="special"><<(</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">basic_ostream</phrase><phrase role="special"><</phrase> <phrase role="identifier">charT</phrase><phrase role="special">,</phrase> <phrase role="identifier">traitsT</phrase> <phrase role="special">></phrase> <phrase role="special">&,</phrase> <phrase role="identifier">id</phrase> <phrase role="keyword">const</phrase><phrase role="special">&);</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">&</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">&</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<</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">&</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></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">&</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"><</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<=</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">&</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"><</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>=</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">&</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"><</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<<</link>
|
|
</bridgehead>
|
|
<programlisting><phrase role="keyword">template</phrase><phrase role="special"><</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">></phrase>
|
|
<phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">basic_ostream</phrase><phrase role="special"><</phrase> <phrase role="identifier">charT</phrase><phrase role="special">,</phrase> <phrase role="identifier">traitsT</phrase> <phrase role="special">></phrase> <phrase role="special">&</phrase>
|
|
<phrase role="keyword">operator</phrase><phrase role="special"><<(</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">basic_ostream</phrase><phrase role="special"><</phrase> <phrase role="identifier">charT</phrase><phrase role="special">,</phrase> <phrase role="identifier">traitsT</phrase> <phrase role="special">></phrase> <phrase role="special">&</phrase> <phrase role="identifier">os</phrase><phrase role="special">,</phrase> <phrase role="identifier">id</phrase> <phrase role="keyword">const</phrase><phrase role="special">&</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 — the fiber on which function
|
|
<code><phrase role="identifier">main</phrase><phrase role="special">()</phrase></code>
|
|
is entered — as well as from an explicitly-launched thread’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"><</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">></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"><</phrase> <phrase role="identifier">Clock</phrase><phrase role="special">,</phrase> <phrase role="identifier">Duration</phrase> <phrase role="special">></phrase> <phrase role="keyword">const</phrase><phrase role="special">&);</phrase>
|
|
<phrase role="keyword">template</phrase><phrase role="special"><</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">></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"><</phrase> <phrase role="identifier">Rep</phrase><phrase role="special">,</phrase> <phrase role="identifier">Period</phrase> <phrase role="special">></phrase> <phrase role="keyword">const</phrase><phrase role="special">&);</phrase>
|
|
<phrase role="keyword">template</phrase><phrase role="special"><</phrase> <phrase role="keyword">typename</phrase> <phrase role="identifier">PROPS</phrase> <phrase role="special">></phrase>
|
|
<phrase role="identifier">PROPS</phrase> <phrase role="special">&</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"><</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">></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"><</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">></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"><</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">></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"><</phrase> <phrase role="identifier">Clock</phrase><phrase role="special">,</phrase> <phrase role="identifier">Duration</phrase> <phrase role="special">></phrase> <phrase role="keyword">const</phrase><phrase role="special">&</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"><</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">></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"><</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">></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"><</phrase> <phrase role="identifier">Rep</phrase><phrase role="special">,</phrase> <phrase role="identifier">Period</phrase> <phrase role="special">></phrase> <phrase role="keyword">const</phrase><phrase role="special">&</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"><</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">></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"><</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">></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"><</phrase> <phrase role="keyword">typename</phrase> <phrase role="identifier">PROPS</phrase> <phrase role="special">></phrase>
|
|
<phrase role="identifier">PROPS</phrase> <phrase role="special">&</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<></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<></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
|
|
— 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"><</phrase> <phrase role="identifier">my_fiber_scheduler</phrase> <phrase role="special">>();</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"><</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">>(</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"><</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">thread</phrase> <phrase role="special">></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"><</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"><</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">>(</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"><</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">></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">&)</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">&</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>
|
|
— or <link linkend="algorithm_notify"><code>algorithm::notify()</code></link> is called — 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 — like the rest of your
|
|
<code><phrase role="identifier">algorithm</phrase></code> implementation
|
|
— 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"><</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">></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">&)</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">&</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"><</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">></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">&)</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">&&)</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="keyword">operator</phrase><phrase role="special">=(</phrase> <phrase role="identifier">work_stealing</phrase> <phrase role="keyword">const</phrase><phrase role="special">&)</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="keyword">operator</phrase><phrase role="special">=(</phrase> <phrase role="identifier">work_stealing</phrase> <phrase role="special">&&)</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">&)</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">&</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"><</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">></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">&)</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">&</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’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"><</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">></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<></code></link> subclass’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’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’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’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<></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"><</phrase><phrase
|
|
role="identifier">PROPS</phrase><phrase role="special">></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"><</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">></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"><</phrase> <phrase role="keyword">typename</phrase> <phrase role="identifier">PROPS</phrase> <phrase role="special">></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">&)</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">&)</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">&</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">&)</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">&</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’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"><></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">&</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">&</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’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">&</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"><>::</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>’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"><</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">></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">&)</phrase> <phrase role="special">=</phrase> <phrase role="keyword">delete</phrase><phrase role="special">;</phrase>
|
|
<phrase role="identifier">context</phrase> <phrase role="special">&</phrase> <phrase role="keyword">operator</phrase><phrase role="special">=(</phrase> <phrase role="identifier">context</phrase> <phrase role="keyword">const</phrase><phrase role="special">&)</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"><</phrase> <phrase role="keyword">typename</phrase> <phrase role="identifier">List</phrase> <phrase role="special">></phrase>
|
|
<phrase role="keyword">void</phrase> <phrase role="identifier">ready_link</phrase><phrase role="special">(</phrase> <phrase role="identifier">List</phrase> <phrase role="special">&)</phrase> <phrase role="keyword">noexcept</phrase><phrase role="special">;</phrase>
|
|
<phrase role="keyword">template</phrase><phrase role="special"><</phrase> <phrase role="keyword">typename</phrase> <phrase role="identifier">List</phrase> <phrase role="special">></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">&)</phrase> <phrase role="keyword">noexcept</phrase><phrase role="special">;</phrase>
|
|
<phrase role="keyword">template</phrase><phrase role="special"><</phrase> <phrase role="keyword">typename</phrase> <phrase role="identifier">List</phrase> <phrase role="special">></phrase>
|
|
<phrase role="keyword">void</phrase> <phrase role="identifier">wait_link</phrase><phrase role="special">(</phrase> <phrase role="identifier">List</phrase> <phrase role="special">&)</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"><(</phrase> <phrase role="identifier">context</phrase> <phrase role="keyword">const</phrase><phrase role="special">&</phrase> <phrase role="identifier">l</phrase><phrase role="special">,</phrase> <phrase role="identifier">context</phrase> <phrase role="keyword">const</phrase><phrase role="special">&</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">-></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">-></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">()-></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’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’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">-></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">&&</phrase> <phrase role="special">!</phrase>
|
|
<phrase role="keyword">this</phrase><phrase role="special">-></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">-></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’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’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’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’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 — 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>
|
|
— 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’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’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’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"><</phrase> <phrase role="keyword">typename</phrase> <phrase role="identifier">List</phrase> <phrase role="special">></phrase>
|
|
<phrase role="keyword">void</phrase> <phrase role="identifier">ready_link</phrase><phrase role="special">(</phrase> <phrase role="identifier">List</phrase> <phrase role="special">&</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"><</phrase> <phrase role="keyword">typename</phrase> <phrase role="identifier">List</phrase> <phrase role="special">></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">&</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"><</phrase> <phrase role="keyword">typename</phrase> <phrase role="identifier">List</phrase> <phrase role="special">></phrase>
|
|
<phrase role="keyword">void</phrase> <phrase role="identifier">wait_link</phrase><phrase role="special">(</phrase> <phrase role="identifier">List</phrase> <phrase role="special">&</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<()</code></link>
|
|
</bridgehead>
|
|
</para>
|
|
<programlisting><phrase role="keyword">bool</phrase> <phrase role="keyword">operator</phrase><phrase role="special"><(</phrase> <phrase role="identifier">context</phrase> <phrase role="keyword">const</phrase><phrase role="special">&</phrase> <phrase role="identifier">l</phrase><phrase role="special">,</phrase> <phrase role="identifier">context</phrase> <phrase role="keyword">const</phrase><phrase role="special">&</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"><</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"><</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">></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">&);</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"><=</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"><=</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">&</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"><=</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"><=</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"><></phrase></code></ulink>.
|
|
</para>
|
|
<programlisting><phrase role="preprocessor">#include</phrase> <phrase role="special"><</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">></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">&);</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">>=</phrase> <phrase role="identifier">stack_size</phrase><phrase
|
|
role="special">)</phrase></code> and <code><phrase role="number">0</phrase>
|
|
<phrase role="special"><</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 — 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">>=</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">&</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">>=</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"><</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">></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">&);</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"><=</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">>=</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">&</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"><=</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">>=</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"><</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">></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">&);</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"><=</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">>=</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">&</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"><=</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">>=</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"><</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">></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">&</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">&</phrase> <phrase role="keyword">operator</phrase><phrase role="special">=(</phrase> <phrase role="identifier">mutex</phrase> <phrase role="keyword">const</phrase><phrase role="special">&</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"><</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">></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">&</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">&</phrase> <phrase role="keyword">operator</phrase><phrase role="special">=(</phrase> <phrase role="identifier">timed_mutex</phrase> <phrase role="keyword">const</phrase><phrase role="special">&</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"><</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">></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"><</phrase> <phrase role="identifier">Clock</phrase><phrase role="special">,</phrase> <phrase role="identifier">Duration</phrase> <phrase role="special">></phrase> <phrase role="keyword">const</phrase><phrase role="special">&</phrase> <phrase role="identifier">timeout_time</phrase><phrase role="special">);</phrase>
|
|
<phrase role="keyword">template</phrase><phrase role="special"><</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">></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"><</phrase> <phrase role="identifier">Rep</phrase><phrase role="special">,</phrase> <phrase role="identifier">Period</phrase> <phrase role="special">></phrase> <phrase role="keyword">const</phrase><phrase role="special">&</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"><</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">></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"><</phrase> <phrase role="identifier">Clock</phrase><phrase role="special">,</phrase> <phrase role="identifier">Duration</phrase> <phrase role="special">></phrase> <phrase role="keyword">const</phrase><phrase role="special">&</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"><</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">></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"><</phrase> <phrase role="identifier">Rep</phrase><phrase role="special">,</phrase> <phrase role="identifier">Period</phrase> <phrase role="special">></phrase> <phrase role="keyword">const</phrase><phrase role="special">&</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"><</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">></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">&</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">&</phrase> <phrase role="keyword">operator</phrase><phrase role="special">=(</phrase> <phrase role="identifier">recursive_mutex</phrase> <phrase role="keyword">const</phrase><phrase role="special">&</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"><</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">></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">&</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">&</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">&</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"><</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">></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"><</phrase> <phrase role="identifier">Clock</phrase><phrase role="special">,</phrase> <phrase role="identifier">Duration</phrase> <phrase role="special">></phrase> <phrase role="keyword">const</phrase><phrase role="special">&</phrase> <phrase role="identifier">timeout_time</phrase><phrase role="special">);</phrase>
|
|
<phrase role="keyword">template</phrase><phrase role="special"><</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">></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"><</phrase> <phrase role="identifier">Rep</phrase><phrase role="special">,</phrase> <phrase role="identifier">Period</phrase> <phrase role="special">></phrase> <phrase role="keyword">const</phrase><phrase role="special">&</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"><</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">></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"><</phrase> <phrase role="identifier">Clock</phrase><phrase role="special">,</phrase> <phrase role="identifier">Duration</phrase> <phrase role="special">></phrase> <phrase role="keyword">const</phrase><phrase role="special">&</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"><</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">></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"><</phrase> <phrase role="identifier">Rep</phrase><phrase role="special">,</phrase> <phrase role="identifier">Period</phrase> <phrase role="special">></phrase> <phrase role="keyword">const</phrase><phrase role="special">&</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"><</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">></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"><</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">></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"><</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">></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"><</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">></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"><</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">></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">&)</phrase> <phrase role="special">=</phrase> <phrase role="keyword">delete</phrase><phrase role="special">;</phrase>
|
|
condition_variable_any <phrase role="special">&</phrase> <phrase role="keyword">operator</phrase><phrase role="special">=(</phrase> condition_variable_any <phrase role="keyword">const</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">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< typename LockType >
|
|
void <phrase role="identifier">wait</phrase><phrase role="special">(</phrase> LockType <phrase role="special">&);</phrase>
|
|
|
|
<phrase role="keyword">template</phrase><phrase role="special"><</phrase> typename LockType, typename <phrase role="identifier">Pred</phrase> <phrase role="special">></phrase>
|
|
<phrase role="keyword">void</phrase> <phrase role="identifier">wait</phrase><phrase role="special">(</phrase> LockType <phrase role="special">&,</phrase> <phrase role="identifier">Pred</phrase><phrase role="special">);</phrase>
|
|
|
|
<phrase role="keyword">template</phrase><phrase role="special"><</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="identifier">cv_status</phrase> <phrase role="identifier">wait_until</phrase><phrase role="special">(</phrase> LockType <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"><</phrase> <phrase role="identifier">Clock</phrase><phrase role="special">,</phrase> <phrase role="identifier">Duration</phrase> <phrase role="special">></phrase> <phrase role="keyword">const</phrase><phrase role="special">&);</phrase>
|
|
|
|
<phrase role="keyword">template</phrase><phrase role="special"><</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">></phrase>
|
|
<phrase role="keyword">bool</phrase> <phrase role="identifier">wait_until</phrase><phrase role="special">(</phrase> LockType <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"><</phrase> <phrase role="identifier">Clock</phrase><phrase role="special">,</phrase> <phrase role="identifier">Duration</phrase> <phrase role="special">></phrase> <phrase role="keyword">const</phrase><phrase role="special">&,</phrase>
|
|
<phrase role="identifier">Pred</phrase><phrase role="special">);</phrase>
|
|
|
|
<phrase role="keyword">template</phrase><phrase role="special"><</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="identifier">cv_status</phrase> <phrase role="identifier">wait_for</phrase><phrase role="special">(</phrase> LockType <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"><</phrase> <phrase role="identifier">Rep</phrase><phrase role="special">,</phrase> <phrase role="identifier">Period</phrase> <phrase role="special">></phrase> <phrase role="keyword">const</phrase><phrase role="special">&);</phrase>
|
|
|
|
<phrase role="keyword">template</phrase><phrase role="special"><</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">></phrase>
|
|
<phrase role="keyword">bool</phrase> <phrase role="identifier">wait_for</phrase><phrase role="special">(</phrase> LockType <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"><</phrase> <phrase role="identifier">Rep</phrase><phrase role="special">,</phrase> <phrase role="identifier">Period</phrase> <phrase role="special">></phrase> <phrase role="keyword">const</phrase><phrase role="special">&,</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< typename LockType >
|
|
void <phrase role="identifier">wait</phrase><phrase role="special">(</phrase> LockType <phrase role="special">&</phrase> <phrase role="identifier">lk</phrase><phrase role="special">);</phrase>
|
|
|
|
<phrase role="keyword">template</phrase><phrase role="special"><</phrase> typename LockType, typename <phrase role="identifier">Pred</phrase> <phrase role="special">></phrase>
|
|
<phrase role="keyword">void</phrase> <phrase role="identifier">wait</phrase><phrase role="special">(</phrase> LockType <phrase role="special">&</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">-></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">-></phrase><phrase role="identifier">notify_one</phrase><phrase
|
|
role="special">()</phrase></code> or <code><phrase role="keyword">this</phrase><phrase
|
|
role="special">-></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"><</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="identifier">cv_status</phrase> <phrase role="identifier">wait_until</phrase><phrase role="special">(</phrase> LockType <phrase role="special">&</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"><</phrase> <phrase role="identifier">Clock</phrase><phrase role="special">,</phrase> <phrase role="identifier">Duration</phrase> <phrase role="special">></phrase> <phrase role="keyword">const</phrase><phrase role="special">&</phrase> <phrase role="identifier">abs_time</phrase><phrase role="special">);</phrase>
|
|
|
|
<phrase role="keyword">template</phrase><phrase role="special"><</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">></phrase>
|
|
<phrase role="keyword">bool</phrase> <phrase role="identifier">wait_until</phrase><phrase role="special">(</phrase> LockType <phrase role="special">&</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"><</phrase> <phrase role="identifier">Clock</phrase><phrase role="special">,</phrase> <phrase role="identifier">Duration</phrase> <phrase role="special">></phrase> <phrase role="keyword">const</phrase><phrase role="special">&</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">-></phrase><phrase role="identifier">notify_one</phrase><phrase
|
|
role="special">()</phrase></code> or <code><phrase role="keyword">this</phrase><phrase
|
|
role="special">-></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"><</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="identifier">cv_status</phrase> <phrase role="identifier">wait_for</phrase><phrase role="special">(</phrase> LockType <phrase role="special">&</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"><</phrase> <phrase role="identifier">Rep</phrase><phrase role="special">,</phrase> <phrase role="identifier">Period</phrase> <phrase role="special">></phrase> <phrase role="keyword">const</phrase><phrase role="special">&</phrase> <phrase role="identifier">rel_time</phrase><phrase role="special">);</phrase>
|
|
|
|
<phrase role="keyword">template</phrase><phrase role="special"><</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">></phrase>
|
|
<phrase role="keyword">bool</phrase> <phrase role="identifier">wait_for</phrase><phrase role="special">(</phrase> LockType <phrase role="special">&</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"><</phrase> <phrase role="identifier">Rep</phrase><phrase role="special">,</phrase> <phrase role="identifier">Period</phrase> <phrase role="special">></phrase> <phrase role="keyword">const</phrase><phrase role="special">&</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">-></phrase><phrase role="identifier">notify_one</phrase><phrase
|
|
role="special">()</phrase></code> or <code><phrase role="keyword">this</phrase><phrase
|
|
role="special">-></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"><</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">></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">&)</phrase> <phrase role="special">=</phrase> <phrase role="keyword">delete</phrase><phrase role="special">;</phrase>
|
|
condition_variable <phrase role="special">&</phrase> <phrase role="keyword">operator</phrase><phrase role="special">=(</phrase> condition_variable <phrase role="keyword">const</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">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< mutex > <phrase role="special">&);</phrase>
|
|
|
|
<phrase role="keyword">template</phrase><phrase role="special"><</phrase> typename <phrase role="identifier">Pred</phrase> <phrase role="special">></phrase>
|
|
<phrase role="keyword">void</phrase> <phrase role="identifier">wait</phrase><phrase role="special">(</phrase> std::unique_lock< mutex > <phrase role="special">&,</phrase> <phrase role="identifier">Pred</phrase><phrase role="special">);</phrase>
|
|
|
|
<phrase role="keyword">template</phrase><phrase role="special"><</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="identifier">cv_status</phrase> <phrase role="identifier">wait_until</phrase><phrase role="special">(</phrase> std::unique_lock< mutex > <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"><</phrase> <phrase role="identifier">Clock</phrase><phrase role="special">,</phrase> <phrase role="identifier">Duration</phrase> <phrase role="special">></phrase> <phrase role="keyword">const</phrase><phrase role="special">&);</phrase>
|
|
|
|
<phrase role="keyword">template</phrase><phrase role="special"><</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">></phrase>
|
|
<phrase role="keyword">bool</phrase> <phrase role="identifier">wait_until</phrase><phrase role="special">(</phrase> std::unique_lock< mutex > <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"><</phrase> <phrase role="identifier">Clock</phrase><phrase role="special">,</phrase> <phrase role="identifier">Duration</phrase> <phrase role="special">></phrase> <phrase role="keyword">const</phrase><phrase role="special">&,</phrase>
|
|
<phrase role="identifier">Pred</phrase><phrase role="special">);</phrase>
|
|
|
|
<phrase role="keyword">template</phrase><phrase role="special"><</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="identifier">cv_status</phrase> <phrase role="identifier">wait_for</phrase><phrase role="special">(</phrase> std::unique_lock< mutex > <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"><</phrase> <phrase role="identifier">Rep</phrase><phrase role="special">,</phrase> <phrase role="identifier">Period</phrase> <phrase role="special">></phrase> <phrase role="keyword">const</phrase><phrase role="special">&);</phrase>
|
|
|
|
<phrase role="keyword">template</phrase><phrase role="special"><</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">></phrase>
|
|
<phrase role="keyword">bool</phrase> <phrase role="identifier">wait_for</phrase><phrase role="special">(</phrase> std::unique_lock< mutex > <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"><</phrase> <phrase role="identifier">Rep</phrase><phrase role="special">,</phrase> <phrase role="identifier">Period</phrase> <phrase role="special">></phrase> <phrase role="keyword">const</phrase><phrase role="special">&,</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< mutex > <phrase role="special">&</phrase> <phrase role="identifier">lk</phrase><phrase role="special">);</phrase>
|
|
|
|
<phrase role="keyword">template</phrase><phrase role="special"><</phrase> typename <phrase role="identifier">Pred</phrase> <phrase role="special">></phrase>
|
|
<phrase role="keyword">void</phrase> <phrase role="identifier">wait</phrase><phrase role="special">(</phrase> std::unique_lock< mutex > <phrase role="special">&</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">-></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">-></phrase><phrase role="identifier">notify_one</phrase><phrase
|
|
role="special">()</phrase></code> or <code><phrase role="keyword">this</phrase><phrase
|
|
role="special">-></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"><</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="identifier">cv_status</phrase> <phrase role="identifier">wait_until</phrase><phrase role="special">(</phrase> std::unique_lock< mutex > <phrase role="special">&</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"><</phrase> <phrase role="identifier">Clock</phrase><phrase role="special">,</phrase> <phrase role="identifier">Duration</phrase> <phrase role="special">></phrase> <phrase role="keyword">const</phrase><phrase role="special">&</phrase> <phrase role="identifier">abs_time</phrase><phrase role="special">);</phrase>
|
|
|
|
<phrase role="keyword">template</phrase><phrase role="special"><</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">></phrase>
|
|
<phrase role="keyword">bool</phrase> <phrase role="identifier">wait_until</phrase><phrase role="special">(</phrase> std::unique_lock< mutex > <phrase role="special">&</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"><</phrase> <phrase role="identifier">Clock</phrase><phrase role="special">,</phrase> <phrase role="identifier">Duration</phrase> <phrase role="special">></phrase> <phrase role="keyword">const</phrase><phrase role="special">&</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">-></phrase><phrase role="identifier">notify_one</phrase><phrase
|
|
role="special">()</phrase></code> or <code><phrase role="keyword">this</phrase><phrase
|
|
role="special">-></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"><</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="identifier">cv_status</phrase> <phrase role="identifier">wait_for</phrase><phrase role="special">(</phrase> std::unique_lock< mutex > <phrase role="special">&</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"><</phrase> <phrase role="identifier">Rep</phrase><phrase role="special">,</phrase> <phrase role="identifier">Period</phrase> <phrase role="special">></phrase> <phrase role="keyword">const</phrase><phrase role="special">&</phrase> <phrase role="identifier">rel_time</phrase><phrase role="special">);</phrase>
|
|
|
|
<phrase role="keyword">template</phrase><phrase role="special"><</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">></phrase>
|
|
<phrase role="keyword">bool</phrase> <phrase role="identifier">wait_for</phrase><phrase role="special">(</phrase> std::unique_lock< mutex > <phrase role="special">&</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"><</phrase> <phrase role="identifier">Rep</phrase><phrase role="special">,</phrase> <phrase role="identifier">Period</phrase> <phrase role="special">></phrase> <phrase role="keyword">const</phrase><phrase role="special">&</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">-></phrase><phrase role="identifier">notify_one</phrase><phrase
|
|
role="special">()</phrase></code> or <code><phrase role="keyword">this</phrase><phrase
|
|
role="special">-></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"><</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">></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">&)</phrase> <phrase role="special">=</phrase> <phrase role="keyword">delete</phrase><phrase role="special">;</phrase>
|
|
<phrase role="identifier">barrier</phrase> <phrase role="special">&</phrase> <phrase role="keyword">operator</phrase><phrase role="special">=(</phrase> <phrase role="identifier">barrier</phrase> <phrase role="keyword">const</phrase><phrase role="special">&)</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"><</phrase> <phrase role="keyword">int</phrase> <phrase role="special">></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">&</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"><</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">&</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"><<</phrase> <phrase role="string">"received "</phrase> <phrase role="special"><<</phrase> <phrase role="identifier">i</phrase> <phrase role="special"><<</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"><</phrase> <phrase role="keyword">int</phrase> <phrase role="special">></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">&</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">&</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"><<</phrase> <phrase role="identifier">value</phrase> <phrase role="special"><<</phrase> <phrase role="string">" "</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"><<</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<></code></link>
|
|
</bridgehead>
|
|
</para>
|
|
<programlisting><phrase role="preprocessor">#include</phrase> <phrase role="special"><</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">></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"><</phrase> <phrase role="keyword">typename</phrase> <phrase role="identifier">T</phrase> <phrase role="special">></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">&</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">&</phrase> <phrase role="keyword">operator</phrase><phrase role="special">=(</phrase> <phrase role="identifier">buffered_channel</phrase> <phrase role="keyword">const</phrase><phrase role="special">&</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">&</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">&&</phrase> <phrase role="identifier">va</phrase><phrase role="special">);</phrase>
|
|
<phrase role="keyword">template</phrase><phrase role="special"><</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">></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">&</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"><</phrase> <phrase role="identifier">Rep</phrase><phrase role="special">,</phrase> <phrase role="identifier">Period</phrase> <phrase role="special">></phrase> <phrase role="keyword">const</phrase><phrase role="special">&</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">&&</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"><</phrase> <phrase role="identifier">Rep</phrase><phrase role="special">,</phrase> <phrase role="identifier">Period</phrase> <phrase role="special">></phrase> <phrase role="keyword">const</phrase><phrase role="special">&</phrase> <phrase role="identifier">timeout_duration</phrase><phrase role="special">);</phrase>
|
|
<phrase role="keyword">template</phrase><phrase role="special"><</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">></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">&</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"><</phrase> <phrase role="identifier">Clock</phrase><phrase role="special">,</phrase> <phrase role="identifier">Duration</phrase> <phrase role="special">></phrase> <phrase role="keyword">const</phrase><phrase role="special">&</phrase> <phrase role="identifier">timeout_time</phrase><phrase role="special">);</phrase>
|
|
<phrase role="keyword">template</phrase><phrase role="special"><</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">></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">&&</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"><</phrase> <phrase role="identifier">Clock</phrase><phrase role="special">,</phrase> <phrase role="identifier">Duration</phrase> <phrase role="special">></phrase> <phrase role="keyword">const</phrase><phrase role="special">&</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">&</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">&&</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">&</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"><</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">></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">&</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"><</phrase> <phrase role="identifier">Rep</phrase><phrase role="special">,</phrase> <phrase role="identifier">Period</phrase> <phrase role="special">></phrase> <phrase role="keyword">const</phrase><phrase role="special">&</phrase> <phrase role="identifier">timeout_duration</phrase><phrase role="special">);</phrase>
|
|
<phrase role="keyword">template</phrase><phrase role="special"><</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">></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">&</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"><</phrase> <phrase role="identifier">Clock</phrase><phrase role="special">,</phrase> <phrase role="identifier">Duration</phrase> <phrase role="special">></phrase> <phrase role="keyword">const</phrase><phrase role="special">&</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">&</phrase> <phrase role="identifier">va</phrase><phrase role="special">);</phrase>
|
|
<phrase role="special">};</phrase>
|
|
|
|
<phrase role="keyword">template</phrase><phrase role="special"><</phrase> <phrase role="keyword">typename</phrase> <phrase role="identifier">T</phrase> <phrase role="special">></phrase>
|
|
<phrase role="identifier">buffered_channel</phrase><phrase role="special"><</phrase> <phrase role="identifier">T</phrase> <phrase role="special">>::</phrase><phrase role="identifier">iterator</phrase> <phrase role="identifier">begin</phrase><phrase role="special">(</phrase> <phrase role="identifier">buffered_channel</phrase><phrase role="special"><</phrase> <phrase role="identifier">T</phrase> <phrase role="special">></phrase> <phrase role="special">&</phrase> <phrase role="identifier">chan</phrase><phrase role="special">);</phrase>
|
|
|
|
<phrase role="keyword">template</phrase><phrase role="special"><</phrase> <phrase role="keyword">typename</phrase> <phrase role="identifier">T</phrase> <phrase role="special">></phrase>
|
|
<phrase role="identifier">buffered_channel</phrase><phrase role="special"><</phrase> <phrase role="identifier">T</phrase> <phrase role="special">>::</phrase><phrase role="identifier">iterator</phrase> <phrase role="identifier">end</phrase><phrase role="special">(</phrase> <phrase role="identifier">buffered_channel</phrase><phrase role="special"><</phrase> <phrase role="identifier">T</phrase> <phrase role="special">></phrase> <phrase role="special">&</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"><=</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">&</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">&</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">-></phrase><phrase
|
|
role="identifier">close</phrase><phrase role="special">()</phrase></code>.
|
|
Fibers blocked in <code><phrase role="keyword">this</phrase><phrase
|
|
role="special">-></phrase><phrase role="identifier">pop</phrase><phrase
|
|
role="special">()</phrase></code>, <code><phrase role="keyword">this</phrase><phrase
|
|
role="special">-></phrase><phrase role="identifier">pop_wait_for</phrase><phrase
|
|
role="special">()</phrase></code> or <code><phrase role="keyword">this</phrase><phrase
|
|
role="special">-></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">-></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">&</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">&&</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">-></phrase><phrase
|
|
role="identifier">pop</phrase><phrase role="special">()</phrase></code>,
|
|
<code><phrase role="keyword">this</phrase><phrase role="special">-></phrase><phrase
|
|
role="identifier">value_pop</phrase><phrase role="special">()</phrase></code>,
|
|
<code><phrase role="keyword">this</phrase><phrase role="special">-></phrase><phrase
|
|
role="identifier">pop_wait_for</phrase><phrase role="special">()</phrase></code>
|
|
or <code><phrase role="keyword">this</phrase><phrase role="special">-></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">&</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">&&</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">-></phrase><phrase
|
|
role="identifier">pop</phrase><phrase role="special">()</phrase></code>,
|
|
<code><phrase role="keyword">this</phrase><phrase role="special">-></phrase><phrase
|
|
role="identifier">value_pop</phrase><phrase role="special">()</phrase></code>,
|
|
<code><phrase role="keyword">this</phrase><phrase role="special">-></phrase><phrase
|
|
role="identifier">pop_wait_for</phrase><phrase role="special">()</phrase></code>
|
|
or <code><phrase role="keyword">this</phrase><phrase role="special">-></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">&</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">&</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"><</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">></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">&</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"><</phrase> <phrase role="identifier">Rep</phrase><phrase role="special">,</phrase> <phrase role="identifier">Period</phrase> <phrase role="special">></phrase> <phrase role="keyword">const</phrase><phrase role="special">&</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"><</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">></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">&</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"><</phrase> <phrase role="identifier">Clock</phrase><phrase role="special">,</phrase> <phrase role="identifier">Duration</phrase> <phrase role="special">></phrase> <phrase role="keyword">const</phrase><phrase role="special">&</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"><</phrase>
|
|
<phrase role="identifier">Clock</phrase><phrase role="special">,</phrase>
|
|
<phrase role="identifier">Duration</phrase> <phrase role="special">></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"><</phrase>
|
|
<phrase role="identifier">T</phrase> <phrase role="special">></phrase>
|
|
<phrase role="special">&)</phrase></code></link>
|
|
</bridgehead>
|
|
<programlisting><phrase role="keyword">template</phrase><phrase role="special"><</phrase> <phrase role="keyword">typename</phrase> <phrase role="identifier">T</phrase> <phrase role="special">></phrase>
|
|
<phrase role="identifier">buffered_channel</phrase><phrase role="special"><</phrase> <phrase role="identifier">T</phrase> <phrase role="special">>::</phrase><phrase role="identifier">iterator</phrase> <phrase role="identifier">begin</phrase><phrase role="special">(</phrase> <phrase role="identifier">buffered_channel</phrase><phrase role="special"><</phrase> <phrase role="identifier">T</phrase> <phrase role="special">></phrase> <phrase role="special">&);</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"><</phrase>
|
|
<phrase role="identifier">T</phrase> <phrase role="special">></phrase>
|
|
<phrase role="special">&)</phrase></code></link>
|
|
</bridgehead>
|
|
<programlisting><phrase role="keyword">template</phrase><phrase role="special"><</phrase> <phrase role="keyword">typename</phrase> <phrase role="identifier">T</phrase> <phrase role="special">></phrase>
|
|
<phrase role="identifier">buffered_channel</phrase><phrase role="special"><</phrase> <phrase role="identifier">R</phrase> <phrase role="special">>::</phrase><phrase role="identifier">iterator</phrase> <phrase role="identifier">end</phrase><phrase role="special">(</phrase> <phrase role="identifier">buffered_channel</phrase><phrase role="special"><</phrase> <phrase role="identifier">T</phrase> <phrase role="special">></phrase> <phrase role="special">&);</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"><</phrase> <phrase role="keyword">int</phrase> <phrase role="special">></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">&</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"><</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">&</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"><<</phrase> <phrase role="string">"received "</phrase> <phrase role="special"><<</phrase> <phrase role="identifier">i</phrase> <phrase role="special"><<</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"><</phrase> <phrase role="keyword">int</phrase> <phrase role="special">></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">&</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">&</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"><<</phrase> <phrase role="identifier">value</phrase> <phrase role="special"><<</phrase> <phrase role="string">" "</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"><<</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<></code></link>
|
|
</bridgehead>
|
|
</para>
|
|
<programlisting><phrase role="preprocessor">#include</phrase> <phrase role="special"><</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">></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"><</phrase> <phrase role="keyword">typename</phrase> <phrase role="identifier">T</phrase> <phrase role="special">></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">&</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">&</phrase> <phrase role="keyword">operator</phrase><phrase role="special">=(</phrase> <phrase role="identifier">unbuffered_channel</phrase> <phrase role="keyword">const</phrase><phrase role="special">&</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">&</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">&&</phrase> <phrase role="identifier">va</phrase><phrase role="special">);</phrase>
|
|
<phrase role="keyword">template</phrase><phrase role="special"><</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">></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">&</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"><</phrase> <phrase role="identifier">Rep</phrase><phrase role="special">,</phrase> <phrase role="identifier">Period</phrase> <phrase role="special">></phrase> <phrase role="keyword">const</phrase><phrase role="special">&</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">&&</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"><</phrase> <phrase role="identifier">Rep</phrase><phrase role="special">,</phrase> <phrase role="identifier">Period</phrase> <phrase role="special">></phrase> <phrase role="keyword">const</phrase><phrase role="special">&</phrase> <phrase role="identifier">timeout_duration</phrase><phrase role="special">);</phrase>
|
|
<phrase role="keyword">template</phrase><phrase role="special"><</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">></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">&</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"><</phrase> <phrase role="identifier">Clock</phrase><phrase role="special">,</phrase> <phrase role="identifier">Duration</phrase> <phrase role="special">></phrase> <phrase role="keyword">const</phrase><phrase role="special">&</phrase> <phrase role="identifier">timeout_time</phrase><phrase role="special">);</phrase>
|
|
<phrase role="keyword">template</phrase><phrase role="special"><</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">></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">&&</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"><</phrase> <phrase role="identifier">Clock</phrase><phrase role="special">,</phrase> <phrase role="identifier">Duration</phrase> <phrase role="special">></phrase> <phrase role="keyword">const</phrase><phrase role="special">&</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">&</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"><</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">></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">&</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"><</phrase> <phrase role="identifier">Rep</phrase><phrase role="special">,</phrase> <phrase role="identifier">Period</phrase> <phrase role="special">></phrase> <phrase role="keyword">const</phrase><phrase role="special">&</phrase> <phrase role="identifier">timeout_duration</phrase><phrase role="special">);</phrase>
|
|
<phrase role="keyword">template</phrase><phrase role="special"><</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">></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">&</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"><</phrase> <phrase role="identifier">Clock</phrase><phrase role="special">,</phrase> <phrase role="identifier">Duration</phrase> <phrase role="special">></phrase> <phrase role="keyword">const</phrase><phrase role="special">&</phrase> <phrase role="identifier">timeout_time</phrase><phrase role="special">);</phrase>
|
|
<phrase role="special">};</phrase>
|
|
|
|
<phrase role="keyword">template</phrase><phrase role="special"><</phrase> <phrase role="keyword">typename</phrase> <phrase role="identifier">T</phrase> <phrase role="special">></phrase>
|
|
<phrase role="identifier">unbuffered_channel</phrase><phrase role="special"><</phrase> <phrase role="identifier">T</phrase> <phrase role="special">>::</phrase><phrase role="identifier">iterator</phrase> <phrase role="identifier">begin</phrase><phrase role="special">(</phrase> <phrase role="identifier">unbuffered_channel</phrase><phrase role="special"><</phrase> <phrase role="identifier">T</phrase> <phrase role="special">></phrase> <phrase role="special">&</phrase> <phrase role="identifier">chan</phrase><phrase role="special">);</phrase>
|
|
|
|
<phrase role="keyword">template</phrase><phrase role="special"><</phrase> <phrase role="keyword">typename</phrase> <phrase role="identifier">T</phrase> <phrase role="special">></phrase>
|
|
<phrase role="identifier">unbuffered_channel</phrase><phrase role="special"><</phrase> <phrase role="identifier">T</phrase> <phrase role="special">>::</phrase><phrase role="identifier">iterator</phrase> <phrase role="identifier">end</phrase><phrase role="special">(</phrase> <phrase role="identifier">unbuffered_channel</phrase><phrase role="special"><</phrase> <phrase role="identifier">T</phrase> <phrase role="special">></phrase> <phrase role="special">&</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">-></phrase><phrase
|
|
role="identifier">close</phrase><phrase role="special">()</phrase></code>.
|
|
Fibers blocked in <code><phrase role="keyword">this</phrase><phrase
|
|
role="special">-></phrase><phrase role="identifier">pop</phrase><phrase
|
|
role="special">()</phrase></code>, <code><phrase role="keyword">this</phrase><phrase
|
|
role="special">-></phrase><phrase role="identifier">pop_wait_for</phrase><phrase
|
|
role="special">()</phrase></code> or <code><phrase role="keyword">this</phrase><phrase
|
|
role="special">-></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">-></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">&</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">&&</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">-></phrase><phrase
|
|
role="identifier">pop</phrase><phrase role="special">()</phrase></code>,
|
|
<code><phrase role="keyword">this</phrase><phrase role="special">-></phrase><phrase
|
|
role="identifier">value_pop</phrase><phrase role="special">()</phrase></code>,
|
|
<code><phrase role="keyword">this</phrase><phrase role="special">-></phrase><phrase
|
|
role="identifier">pop_wait_for</phrase><phrase role="special">()</phrase></code>
|
|
or <code><phrase role="keyword">this</phrase><phrase role="special">-></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">&</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"><</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">></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">&</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"><</phrase> <phrase role="identifier">Rep</phrase><phrase role="special">,</phrase> <phrase role="identifier">Period</phrase> <phrase role="special">></phrase> <phrase role="keyword">const</phrase><phrase role="special">&</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"><</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">></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">&</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"><</phrase> <phrase role="identifier">Clock</phrase><phrase role="special">,</phrase> <phrase role="identifier">Duration</phrase> <phrase role="special">></phrase> <phrase role="keyword">const</phrase><phrase role="special">&</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"><</phrase>
|
|
<phrase role="identifier">Clock</phrase><phrase role="special">,</phrase>
|
|
<phrase role="identifier">Duration</phrase> <phrase role="special">></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"><</phrase>
|
|
<phrase role="identifier">T</phrase> <phrase role="special">></phrase>
|
|
<phrase role="special">&)</phrase></code></link>
|
|
</bridgehead>
|
|
<programlisting><phrase role="keyword">template</phrase><phrase role="special"><</phrase> <phrase role="keyword">typename</phrase> <phrase role="identifier">T</phrase> <phrase role="special">></phrase>
|
|
<phrase role="identifier">unbuffered_channel</phrase><phrase role="special"><</phrase> <phrase role="identifier">T</phrase> <phrase role="special">>::</phrase><phrase role="identifier">iterator</phrase> <phrase role="identifier">begin</phrase><phrase role="special">(</phrase> <phrase role="identifier">unbuffered_channel</phrase><phrase role="special"><</phrase> <phrase role="identifier">T</phrase> <phrase role="special">></phrase> <phrase role="special">&);</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"><</phrase>
|
|
<phrase role="identifier">T</phrase> <phrase role="special">></phrase>
|
|
<phrase role="special">&)</phrase></code></link>
|
|
</bridgehead>
|
|
<programlisting><phrase role="keyword">template</phrase><phrase role="special"><</phrase> <phrase role="keyword">typename</phrase> <phrase role="identifier">T</phrase> <phrase role="special">></phrase>
|
|
<phrase role="identifier">unbuffered_channel</phrase><phrase role="special"><</phrase> <phrase role="identifier">R</phrase> <phrase role="special">>::</phrase><phrase role="identifier">iterator</phrase> <phrase role="identifier">end</phrase><phrase role="special">(</phrase> <phrase role="identifier">unbuffered_channel</phrase><phrase role="special"><</phrase> <phrase role="identifier">T</phrase> <phrase role="special">></phrase> <phrase role="special">&);</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<></code></link> and
|
|
<link linkend="class_shared_future"><code>shared_future<></code></link> which are used to retrieve the asynchronous
|
|
results, and <link linkend="class_promise"><code>promise<></code></link> and <link linkend="class_packaged_task"><code>packaged_task<></code></link> which
|
|
are used to generate the asynchronous results.
|
|
</para>
|
|
<para>
|
|
An instance of <link linkend="class_future"><code>future<></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<></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<></code></link> into an instance
|
|
of <link linkend="class_shared_future"><code>shared_future<></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<></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<></code></link> or
|
|
a <link linkend="class_packaged_task"><code>packaged_task<></code></link>. A <link linkend="class_packaged_task"><code>packaged_task<></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<></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<></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"><</phrase><phrase role="keyword">int</phrase><phrase role="special">()></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"><</phrase><phrase role="keyword">int</phrase><phrase role="special">></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<></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"><</phrase><phrase role="keyword">int</phrase><phrase role="special">></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"><</phrase><phrase role="keyword">int</phrase><phrase role="special">></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<></code></link> and its <link linkend="class_future"><code>future<></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<></code></link>.
|
|
</para>
|
|
<para>
|
|
Aside from its originating <code><phrase role="identifier">promise</phrase><phrase
|
|
role="special"><></phrase></code>, a <link linkend="class_future"><code>future<></code></link> holds
|
|
a unique reference to a particular shared state. However, multiple <link linkend="class_shared_future"><code>shared_future<></code></link> instances
|
|
can reference the same underlying shared state.
|
|
</para>
|
|
<para>
|
|
As <link linkend="class_packaged_task"><code>packaged_task<></code></link> and <link linkend="fibers_async"><code>fibers::async()</code></link> are
|
|
implemented using <link linkend="class_promise"><code>promise<></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<></code></link>
|
|
</bridgehead>
|
|
</para>
|
|
<para>
|
|
A <link linkend="class_future"><code>future<></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"><</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">></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"><</phrase> <phrase role="keyword">typename</phrase> <phrase role="identifier">R</phrase> <phrase role="special">></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">&</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="keyword">operator</phrase><phrase role="special">=(</phrase> <phrase role="identifier">future</phrase> <phrase role="keyword">const</phrase><phrase role="special">&</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">&&</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">&</phrase> <phrase role="keyword">operator</phrase><phrase role="special">=(</phrase> <phrase role="identifier">future</phrase> <phrase role="special">&&</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"><</phrase> <phrase role="identifier">R</phrase> <phrase role="special">></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">&</phrase> <phrase role="identifier">get</phrase><phrase role="special">();</phrase> <phrase role="comment">// member only of future< R & > template specialization</phrase>
|
|
<phrase role="keyword">void</phrase> <phrase role="identifier">get</phrase><phrase role="special">();</phrase> <phrase role="comment">// member only of future< void > 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"><</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">></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"><</phrase> <phrase role="identifier">Rep</phrase><phrase role="special">,</phrase> <phrase role="identifier">Period</phrase> <phrase role="special">></phrase> <phrase role="keyword">const</phrase><phrase role="special">&</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"><</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">></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"><</phrase> <phrase role="identifier">Clock</phrase><phrase role="special">,</phrase> <phrase role="identifier">Duration</phrase> <phrase role="special">></phrase> <phrase role="keyword">const</phrase><phrase role="special">&</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">&&</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<></code></link>
|
|
</simpara>
|
|
</listitem>
|
|
<listitem>
|
|
<simpara>
|
|
obtain its <code><phrase role="identifier">future</phrase><phrase role="special"><></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"><></phrase></code>
|
|
</simpara>
|
|
</listitem>
|
|
<listitem>
|
|
<simpara>
|
|
destroy <code><phrase role="identifier">future</phrase><phrase role="special"><></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"><></phrase></code>
|
|
can be obtained from that <code><phrase role="identifier">promise</phrase><phrase
|
|
role="special"><></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">&</phrase> <phrase role="keyword">operator</phrase><phrase role="special">=(</phrase> <phrase role="identifier">future</phrase> <phrase role="special">&&</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"><</phrase> <phrase role="identifier">R</phrase> <phrase role="special">></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<></code></link>.
|
|
</para>
|
|
</listitem>
|
|
</varlistentry>
|
|
<varlistentry>
|
|
<term>Returns:</term>
|
|
<listitem>
|
|
<para>
|
|
a <link linkend="class_shared_future"><code>shared_future<></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">&</phrase> <phrase role="identifier">get</phrase><phrase role="special">();</phrase> <phrase role="comment">// member only of future< R & > template specialization</phrase>
|
|
<phrase role="keyword">void</phrase> <phrase role="identifier">get</phrase><phrase role="special">();</phrase> <phrase role="comment">// member only of future< void > 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"><</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">></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"><</phrase> <phrase role="identifier">Rep</phrase><phrase role="special">,</phrase> <phrase role="identifier">Period</phrase> <phrase role="special">></phrase> <phrase role="keyword">const</phrase><phrase role="special">&</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"><</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">></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"><</phrase> <phrase role="identifier">Clock</phrase><phrase role="special">,</phrase> <phrase role="identifier">Duration</phrase> <phrase role="special">></phrase> <phrase role="keyword">const</phrase><phrase role="special">&</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<></code></link>
|
|
</bridgehead>
|
|
</para>
|
|
<para>
|
|
A <link linkend="class_shared_future"><code>shared_future<></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<></code></link> instances.
|
|
</para>
|
|
<programlisting><phrase role="preprocessor">#include</phrase> <phrase role="special"><</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">></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"><</phrase> <phrase role="keyword">typename</phrase> <phrase role="identifier">R</phrase> <phrase role="special">></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">&</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"><</phrase> <phrase role="identifier">R</phrase> <phrase role="special">></phrase> <phrase role="special">&&</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">&&</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="keyword">operator</phrase><phrase role="special">=(</phrase> <phrase role="identifier">shared_future</phrase> <phrase role="special">&&</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="keyword">operator</phrase><phrase role="special">=(</phrase> <phrase role="identifier">future</phrase><phrase role="special"><</phrase> <phrase role="identifier">R</phrase> <phrase role="special">></phrase> <phrase role="special">&&</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="keyword">operator</phrase><phrase role="special">=(</phrase> <phrase role="identifier">shared_future</phrase> <phrase role="keyword">const</phrase><phrase role="special">&</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">&</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">&</phrase> <phrase role="identifier">get</phrase><phrase role="special">();</phrase> <phrase role="comment">// member only of shared_future< R & > 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< void > 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"><</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">></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"><</phrase> <phrase role="identifier">Rep</phrase><phrase role="special">,</phrase> <phrase role="identifier">Period</phrase> <phrase role="special">></phrase> <phrase role="keyword">const</phrase><phrase role="special">&</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"><</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">></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"><</phrase> <phrase role="identifier">Clock</phrase><phrase role="special">,</phrase> <phrase role="identifier">Duration</phrase> <phrase role="special">></phrase> <phrase role="keyword">const</phrase><phrase role="special">&</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"><</phrase> <phrase role="identifier">R</phrase> <phrase role="special">></phrase> <phrase role="special">&&</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">&&</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">&</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">&</phrase> <phrase role="keyword">operator</phrase><phrase role="special">=(</phrase> <phrase role="identifier">future</phrase><phrase role="special"><</phrase> <phrase role="identifier">R</phrase> <phrase role="special">></phrase> <phrase role="special">&&</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="keyword">operator</phrase><phrase role="special">=(</phrase> <phrase role="identifier">shared_future</phrase> <phrase role="special">&&</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="keyword">operator</phrase><phrase role="special">=(</phrase> <phrase role="identifier">shared_future</phrase> <phrase role="keyword">const</phrase><phrase role="special">&</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">&</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">&</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">&</phrase> <phrase role="identifier">get</phrase><phrase role="special">();</phrase> <phrase role="comment">// member only of shared_future< R & > 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< void > 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"><</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">></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"><</phrase> <phrase role="identifier">Rep</phrase><phrase role="special">,</phrase> <phrase role="identifier">Period</phrase> <phrase role="special">></phrase> <phrase role="keyword">const</phrase><phrase role="special">&</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"><</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">></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"><</phrase> <phrase role="identifier">Clock</phrase><phrase role="special">,</phrase> <phrase role="identifier">Duration</phrase> <phrase role="special">></phrase> <phrase role="keyword">const</phrase><phrase role="special">&</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"><</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">></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"><</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">></phrase>
|
|
<phrase role="identifier">future</phrase><phrase role="special"><</phrase>
|
|
<phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">result_of_t</phrase><phrase role="special"><</phrase>
|
|
<phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">decay_t</phrase><phrase role="special"><</phrase> <phrase role="identifier">Function</phrase> <phrase role="special">>(</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">decay_t</phrase><phrase role="special"><</phrase> <phrase role="identifier">Args</phrase> <phrase role="special">></phrase> <phrase role="special">...</phrase> <phrase role="special">)</phrase>
|
|
<phrase role="special">></phrase>
|
|
<phrase role="special">></phrase>
|
|
<phrase role="identifier">async</phrase><phrase role="special">(</phrase> <phrase role="identifier">Function</phrase> <phrase role="special">&&</phrase> <phrase role="identifier">fn</phrase><phrase role="special">,</phrase> <phrase role="identifier">Args</phrase> <phrase role="special">&&</phrase> <phrase role="special">...</phrase> <phrase role="identifier">args</phrase><phrase role="special">);</phrase>
|
|
|
|
<phrase role="keyword">template</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">></phrase>
|
|
<phrase role="identifier">future</phrase><phrase role="special"><</phrase>
|
|
<phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">result_of_t</phrase><phrase role="special"><</phrase>
|
|
<phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">decay_t</phrase><phrase role="special"><</phrase> <phrase role="identifier">Function</phrase> <phrase role="special">>(</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">decay_t</phrase><phrase role="special"><</phrase> <phrase role="identifier">Args</phrase> <phrase role="special">></phrase> <phrase role="special">...</phrase> <phrase role="special">)</phrase>
|
|
<phrase role="special">></phrase>
|
|
<phrase role="special">></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">&&</phrase> <phrase role="identifier">fn</phrase><phrase role="special">,</phrase> <phrase role="identifier">Args</phrase> <phrase role="special">&&</phrase> <phrase role="special">...</phrase> <phrase role="identifier">args</phrase><phrase role="special">);</phrase>
|
|
|
|
<phrase role="keyword">template</phrase><phrase role="special"><</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">></phrase>
|
|
<phrase role="identifier">future</phrase><phrase role="special"><</phrase>
|
|
<phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">result_of_t</phrase><phrase role="special"><</phrase>
|
|
<phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">decay_t</phrase><phrase role="special"><</phrase> <phrase role="identifier">Function</phrase> <phrase role="special">>(</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">decay_t</phrase><phrase role="special"><</phrase> <phrase role="identifier">Args</phrase> <phrase role="special">></phrase> <phrase role="special">...</phrase> <phrase role="special">)</phrase>
|
|
<phrase role="special">></phrase>
|
|
<phrase role="special">></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">&&</phrase> <phrase role="identifier">fn</phrase><phrase role="special">,</phrase> <phrase role="identifier">Args</phrase> <phrase role="special">&&</phrase> <phrase role="special">...</phrase> <phrase role="identifier">args</phrase><phrase role="special">);</phrase>
|
|
|
|
<phrase role="keyword">template</phrase><phrase role="special"><</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">></phrase>
|
|
<phrase role="identifier">future</phrase><phrase role="special"><</phrase>
|
|
<phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">result_of_t</phrase><phrase role="special"><</phrase>
|
|
<phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">decay_t</phrase><phrase role="special"><</phrase> <phrase role="identifier">Function</phrase> <phrase role="special">>(</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">decay_t</phrase><phrase role="special"><</phrase> <phrase role="identifier">Args</phrase> <phrase role="special">></phrase> <phrase role="special">...</phrase> <phrase role="special">)</phrase>
|
|
<phrase role="special">></phrase>
|
|
<phrase role="special">></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">&&</phrase> <phrase role="identifier">fn</phrase><phrase role="special">,</phrase> <phrase role="identifier">Args</phrase> <phrase role="special">&&</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<></code></link>.
|
|
</para>
|
|
</listitem>
|
|
</varlistentry>
|
|
<varlistentry>
|
|
<term>Result:</term>
|
|
<listitem>
|
|
<para>
|
|
<programlisting><phrase role="identifier">future</phrase><phrase role="special"><</phrase>
|
|
<phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">result_of_t</phrase><phrase role="special"><</phrase>
|
|
<phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">decay_t</phrase><phrase role="special"><</phrase> <phrase role="identifier">Function</phrase> <phrase role="special">>(</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">decay_t</phrase><phrase role="special"><</phrase> <phrase role="identifier">Args</phrase> <phrase role="special">></phrase> <phrase role="special">...</phrase> <phrase role="special">)</phrase>
|
|
<phrase role="special">></phrase>
|
|
<phrase role="special">></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"><></phrase></code></link></title>
|
|
<para>
|
|
A <link linkend="class_promise"><code>promise<></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<></code></link> object.
|
|
<code><phrase role="identifier">promise</phrase><phrase role="special"><></phrase></code>
|
|
and <code><phrase role="identifier">future</phrase><phrase role="special"><></phrase></code>
|
|
communicate via their underlying <link linkend="shared_state">shared state</link>.
|
|
</para>
|
|
<programlisting><phrase role="preprocessor">#include</phrase> <phrase role="special"><</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">></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"><</phrase> <phrase role="keyword">typename</phrase> <phrase role="identifier">R</phrase> <phrase role="special">></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"><</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">></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">&&)</phrase> <phrase role="keyword">noexcept</phrase><phrase role="special">;</phrase>
|
|
|
|
<phrase role="identifier">promise</phrase> <phrase role="special">&</phrase> <phrase role="keyword">operator</phrase><phrase role="special">=(</phrase> <phrase role="identifier">promise</phrase> <phrase role="special">&&)</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">&)</phrase> <phrase role="special">=</phrase> <phrase role="keyword">delete</phrase><phrase role="special">;</phrase>
|
|
|
|
<phrase role="identifier">promise</phrase> <phrase role="special">&</phrase> <phrase role="keyword">operator</phrase><phrase role="special">=(</phrase> <phrase role="identifier">promise</phrase> <phrase role="keyword">const</phrase><phrase role="special">&)</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">&)</phrase> <phrase role="keyword">noexcept</phrase><phrase role="special">;</phrase>
|
|
|
|
<phrase role="identifier">future</phrase><phrase role="special"><</phrase> <phrase role="identifier">R</phrase> <phrase role="special">></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">&);</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">&&);</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">&);</phrase> <phrase role="comment">// member only of promise< R & > template</phrase>
|
|
<phrase role="keyword">void</phrase> <phrase role="identifier">set_value</phrase><phrase role="special">();</phrase> <phrase role="comment">// member only of promise< void > 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"><</phrase> <phrase role="keyword">typename</phrase> <phrase role="identifier">R</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"><</phrase> <phrase role="identifier">R</phrase> <phrase role="special">></phrase> <phrase role="special">&,</phrase> <phrase role="identifier">promise</phrase><phrase role="special"><</phrase> <phrase role="identifier">R</phrase> <phrase role="special">></phrase> <phrase role="special">&)</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"><</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">></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">&&</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">&</phrase> <phrase role="keyword">operator</phrase><phrase role="special">=(</phrase> <phrase role="identifier">promise</phrase> <phrase role="special">&&</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">&</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"><</phrase> <phrase role="identifier">R</phrase> <phrase role="special">></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<></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">&</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">&&</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">&</phrase> <phrase role="identifier">value</phrase><phrase role="special">);</phrase> <phrase role="comment">// member only of promise< R & > template</phrase>
|
|
<phrase role="keyword">void</phrase> <phrase role="identifier">set_value</phrase><phrase role="special">();</phrase> <phrase role="comment">// member only of promise< void > 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"><</phrase> <phrase role="keyword">typename</phrase> <phrase role="identifier">R</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"><</phrase> <phrase role="identifier">R</phrase> <phrase role="special">></phrase> <phrase role="special">&</phrase> <phrase role="identifier">l</phrase><phrase role="special">,</phrase> <phrase role="identifier">promise</phrase><phrase role="special"><</phrase> <phrase role="identifier">R</phrase> <phrase role="special">></phrase> <phrase role="special">&</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"><></phrase></code></link></title>
|
|
<para>
|
|
A <link linkend="class_packaged_task"><code>packaged_task<></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"><></phrase></code> is like this:
|
|
</para>
|
|
<orderedlist>
|
|
<listitem>
|
|
<simpara>
|
|
Instantiate <code><phrase role="identifier">packaged_task</phrase><phrase
|
|
role="special"><></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<></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"><></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"><></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"><</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">></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"><</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">></phrase>
|
|
<phrase role="keyword">class</phrase> <phrase role="identifier">packaged_task</phrase><phrase role="special"><</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">></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"><</phrase> <phrase role="keyword">typename</phrase> <phrase role="identifier">Fn</phrase> <phrase role="special">></phrase>
|
|
<phrase role="keyword">explicit</phrase> <phrase role="identifier">packaged_task</phrase><phrase role="special">(</phrase> <phrase role="identifier">Fn</phrase> <phrase role="special">&&);</phrase>
|
|
|
|
<phrase role="keyword">template</phrase><phrase role="special"><</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">></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">&,</phrase> <phrase role="identifier">Fn</phrase> <phrase role="special">&&);</phrase>
|
|
|
|
<phrase role="identifier">packaged_task</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="identifier">packaged_task</phrase> <phrase role="special">&</phrase> <phrase role="keyword">operator</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="identifier">packaged_task</phrase><phrase role="special">(</phrase> <phrase role="identifier">packaged_task</phrase> <phrase role="keyword">const</phrase><phrase role="special">&)</phrase> <phrase role="special">=</phrase> <phrase role="keyword">delete</phrase><phrase role="special">;</phrase>
|
|
|
|
<phrase role="identifier">packaged_task</phrase> <phrase role="special">&</phrase> <phrase role="keyword">operator</phrase><phrase role="special">=(</phrase> <phrase role="identifier">packaged_task</phrase> <phrase role="keyword">const</phrase><phrase role="special">&)</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">&)</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"><</phrase> <phrase role="identifier">R</phrase> <phrase role="special">></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"><</phrase> <phrase role="keyword">typename</phrase> <phrase role="identifier">Signature</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"><</phrase> <phrase role="identifier">Signature</phrase> <phrase role="special">></phrase> <phrase role="special">&,</phrase> <phrase role="identifier">packaged_task</phrase><phrase role="special"><</phrase> <phrase role="identifier">Signature</phrase> <phrase role="special">></phrase> <phrase role="special">&)</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"><</phrase> <phrase role="keyword">typename</phrase> <phrase role="identifier">Fn</phrase> <phrase role="special">></phrase>
|
|
<phrase role="keyword">explicit</phrase> <phrase role="identifier">packaged_task</phrase><phrase role="special">(</phrase> <phrase role="identifier">Fn</phrase> <phrase role="special">&&</phrase> <phrase role="identifier">fn</phrase><phrase role="special">);</phrase>
|
|
|
|
<phrase role="keyword">template</phrase><phrase role="special"><</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">></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">&</phrase> <phrase role="identifier">alloc</phrase><phrase role="special">,</phrase> <phrase role="identifier">Fn</phrase> <phrase role="special">&&</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">&&</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">&</phrase> <phrase role="keyword">operator</phrase><phrase role="special">=(</phrase> <phrase role="identifier">packaged_task</phrase> <phrase role="special">&&</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">&</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"><</phrase> <phrase role="identifier">R</phrase> <phrase role="special">></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<></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">&&</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"><</phrase> <phrase role="keyword">typename</phrase> <phrase role="identifier">Signature</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"><</phrase> <phrase role="identifier">Signature</phrase> <phrase role="special">></phrase> <phrase role="special">&</phrase> <phrase role="identifier">l</phrase><phrase role="special">,</phrase> <phrase role="identifier">packaged_task</phrase><phrase role="special"><</phrase> <phrase role="identifier">Signature</phrase> <phrase role="special">></phrase> <phrase role="special">&</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"><</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">></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"><</phrase> <phrase role="keyword">typename</phrase> <phrase role="identifier">T</phrase> <phrase role="special">></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">&)</phrase> <phrase role="special">=</phrase> <phrase role="keyword">delete</phrase><phrase role="special">;</phrase>
|
|
<phrase role="identifier">fiber_specific_ptr</phrase> <phrase role="special">&</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">&)</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">->()</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">*()</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">-></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">-></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">-></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">-></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-></code>()</link>
|
|
</bridgehead>
|
|
</para>
|
|
<programlisting><phrase role="identifier">T</phrase> <phrase role="special">*</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">-></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">-></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">&</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">-></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">-></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">-></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">-></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">-></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">-></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">-></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">-></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">-></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 — 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>’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’s original thread calls <link linkend="algorithm_awakened"><code>algorithm::awakened()</code></link>, passing
|
|
the fiber’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"><</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">>();</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">"abcdefghijklmnopqrstuvwxyz"</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">&</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">&</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">&</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">&</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>< <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> >
|
|
</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"><<</phrase> <phrase role="string">"thread started "</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> <phrase role="special"><<</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"><<</phrase> <phrase role="identifier">buffer</phrase><phrase role="special">.</phrase><phrase role="identifier">str</phrase><phrase role="special">()</phrase> <phrase role="special"><<</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"><</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">>();</phrase> <co id="fiber.migration.c18" linkends="fiber.migration.c19" />
|
|
<phrase role="identifier">b</phrase><phrase role="special">-></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"><<</phrase> <phrase role="string">"fiber "</phrase> <phrase role="special"><<</phrase> <phrase role="identifier">me</phrase> <phrase role="special"><<</phrase> <phrase role="string">" started on thread "</phrase> <phrase role="special"><<</phrase> <phrase role="identifier">my_thread</phrase> <phrase role="special"><<</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"><<</phrase> <phrase role="identifier">buffer</phrase><phrase role="special">.</phrase><phrase role="identifier">str</phrase><phrase role="special">()</phrase> <phrase role="special"><<</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"><</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"><<</phrase> <phrase role="string">"fiber "</phrase> <phrase role="special"><<</phrase> <phrase role="identifier">me</phrase> <phrase role="special"><<</phrase> <phrase role="string">" switched to thread "</phrase> <phrase role="special"><<</phrase> <phrase role="identifier">my_thread</phrase> <phrase role="special"><<</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"><<</phrase> <phrase role="identifier">buffer</phrase><phrase role="special">.</phrase><phrase role="identifier">str</phrase><phrase role="special">()</phrase> <phrase role="special"><<</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’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’s main fiber
|
|
and dispatcher fibers: these may <emphasis>not</emphasis> be shared between
|
|
threads! When we’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’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"><</phrase> <phrase role="keyword">typename</phrase> <phrase role="identifier">Fn</phrase> <phrase role="special">></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">&</phrase> <phrase role="identifier">data</phrase><phrase role="special">,</phrase> <phrase role="identifier">Fn</phrase> <phrase role="special">&&</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"><</phrase> <phrase role="keyword">typename</phrase> <phrase role="identifier">Fn</phrase> <phrase role="special">></phrase>
|
|
<phrase role="keyword">void</phrase> <phrase role="identifier">init_read</phrase><phrase role="special">(</phrase> <phrase role="identifier">Fn</phrase> <phrase role="special">&&</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’s return value to deliver relevant data.
|
|
</para>
|
|
<tip>
|
|
<para>
|
|
<link linkend="class_promise"><code>promise<></code></link> and <link linkend="class_future"><code>future<></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<></code></link> and
|
|
<link linkend="class_future"><code>future<></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">&</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">&</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"><</phrase> <phrase role="identifier">AsyncAPI</phrase><phrase role="special">::</phrase><phrase role="identifier">errorcode</phrase> <phrase role="special">></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"><</phrase> <phrase role="identifier">AsyncAPI</phrase><phrase role="special">::</phrase><phrase role="identifier">errorcode</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">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"><</phrase> <phrase role="identifier">AsyncAPI</phrase><phrase role="special">::</phrase><phrase role="identifier">errorcode</phrase> <phrase role="special">></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="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"><></phrase></code> of correct type.
|
|
</simpara>
|
|
</listitem>
|
|
<listitem>
|
|
<simpara>
|
|
Obtain its <code><phrase role="identifier">future</phrase><phrase role="special"><></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’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">&</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">&</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">"write"</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’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"><></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"><</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">></phrase> <phrase role="identifier">read_ec</phrase><phrase role="special">(</phrase> <phrase role="identifier">AsyncAPI</phrase> <phrase role="special">&</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"><</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">></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"><</phrase> <phrase role="identifier">result_pair</phrase> <phrase role="special">></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"><</phrase> <phrase role="identifier">result_pair</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">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">&</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"><</phrase> <phrase role="identifier">result_pair</phrase> <phrase role="special">></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">&</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"><></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’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’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">&</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"><</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">string</phrase> <phrase role="special">></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"><</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">string</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">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">([&</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">&</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">"read"</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"><</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">string</phrase> <phrase role="special">></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">&</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">"read"</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"><</phrase> <phrase role="identifier">Response</phrase> <phrase role="special">></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">&</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">&</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">"read"</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"><</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">string</phrase> <phrase role="special">></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"><</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">string</phrase> <phrase role="special">></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"><></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">&</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"><</phrase> <phrase role="identifier">PromiseResponse</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"><</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">string</phrase> <phrase role="special">></phrase> <phrase role="identifier">future</phrase><phrase role="special">(</phrase> <phrase role="identifier">promisep</phrase><phrase role="special">-></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’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"><</phrase> <phrase role="special">...,</phrase> <phrase role="keyword">class</phrase> <phrase role="identifier">CompletionToken</phrase> <phrase role="special">></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">&&</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"><</phrase><phrase role="identifier">CompletionToken</phrase><phrase role="special">,</phrase> <phrase role="special">...>::</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"><</phrase><phrase role="keyword">decltype</phrase><phrase role="special">(</phrase><phrase role="identifier">handler</phrase><phrase role="special">)></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’s <code><phrase
|
|
role="identifier">handler_type</phrase><phrase role="special"><></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] "binds" @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">&</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">&</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"><></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<void>. 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"><</phrase> <phrase role="keyword">typename</phrase> <phrase role="identifier">ReturnType</phrase> <phrase role="special">></phrase>
|
|
<phrase role="keyword">struct</phrase> <phrase role="identifier">handler_type</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_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">></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"><</phrase> <phrase role="keyword">void</phrase> <phrase role="special">></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’s a generic <code><phrase role="identifier">yield_handler</phrase><phrase
|
|
role="special"><</phrase><phrase role="identifier">T</phrase><phrase role="special">></phrase></code>
|
|
implementation and a <code><phrase role="identifier">yield_handler</phrase><phrase
|
|
role="special"><</phrase><phrase role="keyword">void</phrase><phrase role="special">></phrase></code>
|
|
specialization. Let’s start with the <code><phrase role="special"><</phrase><phrase
|
|
role="keyword">void</phrase><phrase role="special">></phrase></code> specialization:
|
|
</para>
|
|
<para>
|
|
<programlisting><phrase role="comment">// yield_handler<void> is like yield_handler<T> without value_. In fact it's</phrase>
|
|
<phrase role="comment">// just like yield_handler_base.</phrase>
|
|
<phrase role="keyword">template</phrase><phrase role="special"><></phrase>
|
|
<phrase role="keyword">class</phrase> <phrase role="identifier">yield_handler</phrase><phrase role="special"><</phrase> <phrase role="keyword">void</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="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">&</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"><></phrase></code> traits specialization, instantiates
|
|
a <code><phrase role="identifier">yield_handler</phrase><phrase role="special"><</phrase><phrase
|
|
role="keyword">void</phrase><phrase role="special">></phrase></code> to
|
|
be passed as the actual callback for the async operation. <code><phrase role="identifier">yield_handler</phrase></code>’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<T> (capturing</phrase>
|
|
<phrase role="comment">// a value to return from asio async function) and yield_handler<void> (no</phrase>
|
|
<phrase role="comment">// such value). See yield_handler<T> and its <void> specialization below. Both</phrase>
|
|
<phrase role="comment">// yield_handler<T> and yield_handler<void> 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<yield_handler<>> 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">&</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">&</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">"Must inject yield_completion* "</phrase>
|
|
<phrase role="string">"before calling yield_handler_base::operator()()"</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">"Must inject boost::system::error_code* "</phrase>
|
|
<phrase role="string">"before calling yield_handler_base::operator()()"</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">-></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">-></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">-></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">()-></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
|
|
— 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 — 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"><</phrase><phrase role="keyword">void</phrase><phrase role="special">></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"><>::</phrase><phrase role="identifier">type</phrase></code>:
|
|
in this case, <code><phrase role="identifier">async_result</phrase><phrase
|
|
role="special"><</phrase><phrase role="identifier">yield_handler</phrase><phrase
|
|
role="special"><</phrase><phrase role="keyword">void</phrase><phrase role="special">>></phrase></code>.
|
|
It passes the <code><phrase role="identifier">yield_handler</phrase><phrase
|
|
role="special"><</phrase><phrase role="keyword">void</phrase><phrase role="special">></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<void></phrase>
|
|
<phrase role="comment">// specialization is just like async_result_base.</phrase>
|
|
<phrase role="keyword">template</phrase><phrase role="special"><></phrase>
|
|
<phrase role="keyword">class</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"><</phrase> <phrase role="keyword">void</phrase> <phrase role="special">></phrase> <phrase role="special">></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"><</phrase> <phrase role="keyword">void</phrase> <phrase role="special">></phrase> <phrase role="special">&</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<yield_handler<T>> and</phrase>
|
|
<phrase role="comment">// async_result<yield_handler<void>></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">&</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<>.</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">-></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">&</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">-></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>’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>’s
|
|
constructor sets <code><phrase role="identifier">yield_handler_base</phrase></code>’s
|
|
<code><phrase role="identifier">yield_t</phrase></code>’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"><</phrase><phrase role="keyword">void</phrase><phrase role="special">></phrase></code>
|
|
instance on completion. Let’s say, for the sake of argument, that the actual
|
|
async operation’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’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"><</phrase><phrase
|
|
role="identifier">yield_handler</phrase><phrase role="special"><</phrase><phrase
|
|
role="keyword">void</phrase><phrase role="special">>>::</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"><</phrase><phrase
|
|
role="identifier">yield_handler</phrase><phrase role="special"><</phrase><phrase
|
|
role="keyword">void</phrase><phrase role="special">>>::</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"><</phrase> <phrase role="identifier">mutex_t</phrase> <phrase role="special">></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"><</phrase> <phrase role="identifier">yield_completion</phrase> <phrase role="special">></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"><</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">size_t</phrase> <phrase role="special">></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<spinlock>) 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">()-></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">-></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">-></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"><</phrase><phrase role="keyword">void</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">&)</phrase></code> with an <code><phrase role="identifier">error_code</phrase></code>
|
|
indicating either success or failure. We’ll consider both cases.
|
|
</para>
|
|
<para>
|
|
<code><phrase role="identifier">yield_handler</phrase><phrase role="special"><</phrase><phrase
|
|
role="keyword">void</phrase><phrase role="special">></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">&)</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">&)</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>’s
|
|
async operation completes immediately — 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>
|
|
— 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>’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’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’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 — 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 — <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>’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"><</phrase><phrase
|
|
role="keyword">void</phrase><phrase role="special">>::</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"><>::</phrase><phrase role="identifier">type</phrase></code>
|
|
specifies <code><phrase role="identifier">yield_handler</phrase><phrase role="special"><</phrase><phrase
|
|
role="identifier">T</phrase><phrase role="special">></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"><</phrase><phrase
|
|
role="identifier">T</phrase><phrase role="special">></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<completion token type, signature>::type to decide</phrase>
|
|
<phrase role="comment">// what to instantiate as the actual handler. Below, we specialize</phrase>
|
|
<phrase role="comment">// handler_type< yield_t, ... > to indicate yield_handler<>. 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<> as the actual handler class.</phrase>
|
|
<phrase role="keyword">template</phrase><phrase role="special"><</phrase> <phrase role="keyword">typename</phrase> <phrase role="identifier">T</phrase> <phrase role="special">></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">&</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">&</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">"Must inject value ptr "</phrase>
|
|
<phrase role="string">"before caling yield_handler<T>::operator()()"</phrase><phrase role="special">);</phrase>
|
|
<phrase role="comment">// move the value to async_result<> 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"><</phrase><phrase role="identifier">yield_handler</phrase><phrase
|
|
role="special"><</phrase><phrase role="identifier">T</phrase><phrase role="special">>></phrase></code>:
|
|
</para>
|
|
<para>
|
|
<programlisting><phrase role="comment">// asio constructs an async_result<> instance from the yield_handler specified</phrase>
|
|
<phrase role="comment">// by handler_type<>::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"><</phrase> <phrase role="keyword">typename</phrase> <phrase role="identifier">T</phrase> <phrase role="special">></phrase>
|
|
<phrase role="keyword">class</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"><</phrase> <phrase role="identifier">T</phrase> <phrase role="special">></phrase> <phrase role="special">></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"><</phrase> <phrase role="identifier">T</phrase> <phrase role="special">></phrase> <phrase role="special">&</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<>: 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">&</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"><></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"><</phrase><phrase role="identifier">T</phrase><phrase role="special">>::</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"><</phrase><phrase
|
|
role="identifier">yield_handler</phrase><phrase role="special"><</phrase><phrase
|
|
role="identifier">T</phrase><phrase role="special">>></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"><</phrase><phrase
|
|
role="identifier">T</phrase><phrase role="special">>::</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"><</phrase><phrase
|
|
role="identifier">yield_handler</phrase><phrase role="special"><</phrase><phrase
|
|
role="identifier">T</phrase><phrase role="special">>>::</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"><</phrase><phrase
|
|
role="identifier">yield_handler</phrase><phrase role="special"><</phrase><phrase
|
|
role="identifier">T</phrase><phrase role="special">>>::</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>’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"><</phrase><phrase role="identifier">T</phrase><phrase role="special">>::</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">&</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">&</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">&</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">&</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">&</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"><</phrase> <phrase role="identifier">desired</phrase> <phrase role="special">&&</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">&</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">&</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">&</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"><<</phrase> <phrase role="string">"NonblockingAPI::read() error "</phrase> <phrase role="special"><<</phrase> <phrase role="identifier">ec</phrase> <phrase role="special"><<</phrase> <phrase role="string">" after "</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="string">" of "</phrase> <phrase role="special"><<</phrase> <phrase role="identifier">desired</phrase> <phrase role="special"><<</phrase> <phrase role="string">" characters"</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"><</phrase> <phrase role="keyword">typename</phrase> <phrase role="identifier">T</phrase> <phrase role="special">></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"><<</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"><<</phrase> <phrase role="string">" sleeper("</phrase> <phrase role="special"><<</phrase> <phrase role="identifier">item</phrase> <phrase role="special"><<</phrase> <phrase role="string">")"</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 — 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"><</phrase> <phrase role="identifier">Done</phrase> <phrase role="special">></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"><</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">></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"><</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">></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"><></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"><</phrase> <phrase role="keyword">typename</phrase> <phrase role="special">...</phrase> <phrase role="identifier">Fns</phrase> <phrase role="special">></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">&&</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"><</phrase> <phrase role="identifier">Done</phrase> <phrase role="special">>()</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"><</phrase> <phrase role="identifier">Fns</phrase> <phrase role="special">>(</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">-></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"><</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">></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">&&</phrase> <phrase role="identifier">function</phrase><phrase role="special">,</phrase> <phrase role="identifier">Fns</phrase> <phrase role="special">&&</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">-></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"><</phrase> <phrase role="identifier">Fns</phrase> <phrase role="special">>(</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 — 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"><</phrase><phrase
|
|
role="identifier">Done</phrase><phrase role="special">></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">"wfs_long"</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">"wfs_medium"</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">"wfs_short"</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">"wfs_short"</phrase><phrase role="special">,</phrase>
|
|
<phrase role="number">50</phrase><phrase role="special">)</phrase></code></link>
|
|
completes — 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<></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"><</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">></phrase>
|
|
<phrase role="keyword">typename</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">result_of</phrase><phrase role="special"><</phrase> <phrase role="identifier">Fn</phrase><phrase role="special">()</phrase> <phrase role="special">>::</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">&&</phrase> <phrase role="identifier">function</phrase><phrase role="special">,</phrase> <phrase role="identifier">Fns</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"><</phrase> <phrase role="identifier">Fn</phrase><phrase role="special">()</phrase> <phrase role="special">>::</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"><</phrase> <phrase role="identifier">return_t</phrase> <phrase role="special">></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"><</phrase> <phrase role="identifier">channel_t</phrase> <phrase role="special">>(</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"><</phrase> <phrase role="identifier">return_t</phrase> <phrase role="special">>(</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"><</phrase> <phrase role="identifier">Fn</phrase> <phrase role="special">>(</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"><</phrase> <phrase role="identifier">Fns</phrase> <phrase role="special">>(</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">-></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">-></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"><</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">></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"><</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"><</phrase> <phrase role="identifier">T</phrase> <phrase role="special">></phrase> <phrase role="special">></phrase> <phrase role="identifier">chan</phrase><phrase role="special">,</phrase>
|
|
<phrase role="identifier">Fn</phrase> <phrase role="special">&&</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">-></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">"wfv_third"</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">"wfv_second"</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">"wfv_first"</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"><<</phrase> <phrase role="string">"wait_first_value() => "</phrase> <phrase role="special"><<</phrase> <phrase role="identifier">result</phrase> <phrase role="special"><<</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">"wfv_first"</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<></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<></code></link> to
|
|
hold <code><phrase role="identifier">future</phrase><phrase role="special"><</phrase>
|
|
<phrase role="identifier">T</phrase> <phrase role="special">></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"><></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"><</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">></phrase>
|
|
<phrase role="keyword">typename</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">result_of</phrase><phrase role="special"><</phrase> <phrase role="identifier">Fn</phrase><phrase role="special">()</phrase> <phrase role="special">>::</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">&&</phrase> <phrase role="identifier">function</phrase><phrase role="special">,</phrase> <phrase role="identifier">Fns</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"><</phrase> <phrase role="identifier">Fn</phrase><phrase role="special">()</phrase> <phrase role="special">>::</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"><</phrase> <phrase role="identifier">return_t</phrase> <phrase role="special">></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"><</phrase> <phrase role="identifier">future_t</phrase> <phrase role="special">></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"><</phrase> <phrase role="identifier">channel_t</phrase> <phrase role="special">>(</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"><</phrase> <phrase role="identifier">return_t</phrase> <phrase role="special">>(</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"><</phrase> <phrase role="identifier">Fn</phrase> <phrase role="special">>(</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"><</phrase> <phrase role="identifier">Fns</phrase> <phrase role="special">>(</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">-></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">-></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 — but there's a timing issue. How should we obtain the <code><phrase
|
|
role="identifier">future</phrase><phrase role="special"><></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"><></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"><></phrase></code>
|
|
items for <emphasis>completed</emphasis> tasks on our <code><phrase role="identifier">queue</phrase><phrase
|
|
role="special"><></phrase></code>. In fact, we only want the <code><phrase
|
|
role="identifier">future</phrase><phrase role="special"><></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 — <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"><></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"><></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 — 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<></code></link>.
|
|
While one naturally thinks of passing a <code><phrase role="identifier">packaged_task</phrase><phrase
|
|
role="special"><></phrase></code> to a new fiber — that is, in fact,
|
|
what <code><phrase role="identifier">async</phrase><phrase role="special">()</phrase></code>
|
|
does — 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"><></phrase></code>.
|
|
On return from that call, the task function has completed, meaning that
|
|
the <code><phrase role="identifier">future</phrase><phrase role="special"><></phrase></code>
|
|
obtained from the <code><phrase role="identifier">packaged_task</phrase><phrase
|
|
role="special"><></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"><</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">></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">&&</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">&</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"><</phrase> <phrase role="identifier">Fn</phrase> <phrase role="special">>::</phrase><phrase role="identifier">type</phrase> <phrase role="special">&</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"><</phrase> <phrase role="identifier">T</phrase><phrase role="special">()</phrase> <phrase role="special">></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">-></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"><</phrase> <phrase role="identifier">Fn</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>
|
|
<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">"wfos_first"</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">"wfos_second"</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">"wfos_third"</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"><<</phrase> <phrase role="string">"wait_first_outcome(success) => "</phrase> <phrase role="special"><<</phrase> <phrase role="identifier">result</phrase> <phrase role="special"><<</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">"wfos_first"</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">"wfof_first"</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">"wfof_second"</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">"wfof_third"</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">&</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"><<</phrase> <phrase role="string">"wait_first_outcome(fail) threw '"</phrase> <phrase role="special"><<</phrase> <phrase role="identifier">thrown</phrase>
|
|
<phrase role="special"><<</phrase> <phrase role="string">"'"</phrase> <phrase role="special"><<</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">"wfof_first"</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 — 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"><</phrase>
|
|
<phrase role="identifier">future</phrase><phrase role="special"><</phrase>
|
|
<phrase role="identifier">T</phrase> <phrase role="special">></phrase>
|
|
<phrase role="special">></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">&</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"><</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">exception_ptr</phrase> <phrase role="special">></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"><></phrase></code> from the queue, we must now loop
|
|
over <code><phrase role="identifier">future</phrase><phrase role="special"><></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"><></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"><></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"><></phrase></code> from the queue.
|
|
</para>
|
|
<para>
|
|
If we fall out of the loop — if every single task fiber threw an exception
|
|
— 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"><</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">></phrase>
|
|
<phrase role="keyword">typename</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">result_of</phrase><phrase role="special"><</phrase> <phrase role="identifier">Fn</phrase><phrase role="special">()</phrase> <phrase role="special">>::</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">&&</phrase> <phrase role="identifier">function</phrase><phrase role="special">,</phrase> <phrase role="identifier">Fns</phrase> <phrase role="special">&&</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"><</phrase> <phrase role="keyword">typename</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">decay</phrase><phrase role="special"><</phrase> <phrase role="identifier">Fn</phrase> <phrase role="special">>::</phrase><phrase role="identifier">type</phrase><phrase role="special">()</phrase> <phrase role="special">>::</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"><</phrase> <phrase role="identifier">return_t</phrase> <phrase role="special">></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"><</phrase> <phrase role="identifier">future_t</phrase> <phrase role="special">></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"><</phrase> <phrase role="identifier">channel_t</phrase> <phrase role="special">>(</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"><</phrase> <phrase role="identifier">return_t</phrase> <phrase role="special">>(</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"><</phrase> <phrase role="identifier">Fn</phrase> <phrase role="special">>(</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"><</phrase> <phrase role="identifier">Fns</phrase> <phrase role="special">>(</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">"wait_first_success() produced only errors"</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"><</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">-></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">-></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">"wfss_first"</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">"wfss_second"</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">"wfss_third"</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"><<</phrase> <phrase role="string">"wait_first_success(success) => "</phrase> <phrase role="special"><<</phrase> <phrase role="identifier">result</phrase> <phrase role="special"><<</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">"wfss_second"</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"><</phrase><phrase
|
|
role="identifier">T0</phrase><phrase role="special">,</phrase> <phrase
|
|
role="identifier">T1</phrase><phrase role="special">,</phrase> <phrase
|
|
role="special">...></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<Fn()>::type for each Fn in</phrase>
|
|
<phrase role="comment">// parameter pack.</phrase>
|
|
<phrase role="keyword">template</phrase><phrase role="special"><</phrase> <phrase role="keyword">typename</phrase> <phrase role="special">...</phrase> <phrase role="identifier">Fns</phrase> <phrase role="special">></phrase>
|
|
<phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">variant</phrase><phrase role="special"><</phrase> <phrase role="keyword">typename</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">result_of</phrase><phrase role="special"><</phrase> <phrase role="identifier">Fns</phrase><phrase role="special">()</phrase> <phrase role="special">>::</phrase><phrase role="identifier">type</phrase> <phrase role="special">...</phrase> <phrase role="special">></phrase>
|
|
<phrase role="identifier">wait_first_value_het</phrase><phrase role="special">(</phrase> <phrase role="identifier">Fns</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">// Use buffered_channel<boost::variant<T1, T2, ...>>; 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"><</phrase> <phrase role="keyword">typename</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">result_of</phrase><phrase role="special"><</phrase> <phrase role="identifier">Fns</phrase><phrase role="special">()</phrase> <phrase role="special">>::</phrase><phrase role="identifier">type</phrase> <phrase role="special">...</phrase> <phrase role="special">></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"><</phrase> <phrase role="identifier">return_t</phrase> <phrase role="special">></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"><</phrase> <phrase role="identifier">channel_t</phrase> <phrase role="special">>(</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"><</phrase> <phrase role="identifier">return_t</phrase> <phrase role="special">>(</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"><</phrase> <phrase role="identifier">Fns</phrase> <phrase role="special">>(</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">-></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">-></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"><</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">></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">"wfvh_third"</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"><<</phrase> <phrase role="string">"wait_first_value_het() => "</phrase> <phrase role="special"><<</phrase> <phrase role="identifier">result</phrase> <phrase role="special"><<</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"><</phrase> <phrase role="keyword">int</phrase> <phrase role="special">>(</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 — for purely informational purposes
|
|
— 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<<link linkend="class_promise"><code>promise<></code></link>></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<></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 — but we don't need results (or expect exceptions) from any of
|
|
them — 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"><</phrase> <phrase role="keyword">typename</phrase> <phrase role="special">...</phrase> <phrase role="identifier">Fns</phrase> <phrase role="special">></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">&&</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"><</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">>(</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"><</phrase> <phrase role="identifier">Fns</phrase> <phrase role="special">>(</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">-></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"><</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">></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"><</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">></phrase> <phrase role="identifier">barrier</phrase><phrase role="special">,</phrase>
|
|
<phrase role="identifier">Fn</phrase> <phrase role="special">&&</phrase> <phrase role="identifier">function</phrase><phrase role="special">,</phrase> <phrase role="identifier">Fns</phrase> <phrase role="special">&&</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"><</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">></phrase> <phrase role="special">&</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"><</phrase> <phrase role="identifier">Fn</phrase> <phrase role="special">>::</phrase><phrase role="identifier">type</phrase> <phrase role="special">&</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">-></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"><</phrase> <phrase role="identifier">Fn</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="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"><</phrase> <phrase role="identifier">Fns</phrase> <phrase role="special">>(</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">"was_long"</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">"was_medium"</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">"was_short"</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<T> 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"><</phrase><phrase role="identifier">buffered_channel</phrase><phrase
|
|
role="special"><</phrase><phrase role="identifier">T</phrase><phrase
|
|
role="special">>></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"><</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">></phrase>
|
|
<phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">vector</phrase><phrase role="special"><</phrase> <phrase role="keyword">typename</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">result_of</phrase><phrase role="special"><</phrase> <phrase role="identifier">Fn</phrase><phrase role="special">()</phrase> <phrase role="special">>::</phrase><phrase role="identifier">type</phrase> <phrase role="special">></phrase>
|
|
<phrase role="identifier">wait_all_values</phrase><phrase role="special">(</phrase> <phrase role="identifier">Fn</phrase> <phrase role="special">&&</phrase> <phrase role="identifier">function</phrase><phrase role="special">,</phrase> <phrase role="identifier">Fns</phrase> <phrase role="special">&&</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"><</phrase> <phrase role="identifier">Fn</phrase><phrase role="special">()</phrase> <phrase role="special">>::</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"><</phrase> <phrase role="identifier">return_t</phrase> <phrase role="special">></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"><</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"><</phrase> <phrase role="identifier">return_t</phrase> <phrase role="special">></phrase> <phrase role="special">></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"><</phrase> <phrase role="identifier">Fn</phrase> <phrase role="special">>(</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"><</phrase> <phrase role="identifier">Fns</phrase> <phrase role="special">>(</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">-></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"><</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">string</phrase> <phrase role="special">></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">"wav_late"</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">"wav_middle"</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">"wav_early"</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"><></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"><></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"><</phrase><phrase
|
|
role="identifier">T</phrase><phrase role="special">></phrase></code>
|
|
with an <code><phrase role="identifier">nqueue</phrase><phrase role="special"><</phrase><phrase
|
|
role="identifier">T</phrase><phrase role="special">></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"><</phrase><phrase role="identifier">queue</phrase><phrase
|
|
role="special"><</phrase><phrase role="identifier">T</phrase><phrase
|
|
role="special">>></phrase></code>.
|
|
</para>
|
|
<para>
|
|
<programlisting><phrase role="comment">// Return a shared_ptr<buffered_channel<T>> 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"><</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">></phrase>
|
|
<phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">shared_ptr</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">buffered_channel</phrase><phrase role="special"><</phrase> <phrase role="keyword">typename</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">result_of</phrase><phrase role="special"><</phrase> <phrase role="identifier">Fn</phrase><phrase role="special">()</phrase> <phrase role="special">>::</phrase><phrase role="identifier">type</phrase> <phrase role="special">></phrase> <phrase role="special">></phrase>
|
|
<phrase role="identifier">wait_all_values_source</phrase><phrase role="special">(</phrase> <phrase role="identifier">Fn</phrase> <phrase role="special">&&</phrase> <phrase role="identifier">function</phrase><phrase role="special">,</phrase> <phrase role="identifier">Fns</phrase> <phrase role="special">&&</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"><</phrase> <phrase role="identifier">Fn</phrase><phrase role="special">()</phrase> <phrase role="special">>::</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"><</phrase> <phrase role="identifier">return_t</phrase> <phrase role="special">></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"><</phrase> <phrase role="identifier">channel_t</phrase> <phrase role="special">>(</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"><</phrase> <phrase role="identifier">nchannel</phrase><phrase role="special"><</phrase> <phrase role="identifier">return_t</phrase> <phrase role="special">></phrase> <phrase role="special">>(</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"><</phrase> <phrase role="identifier">return_t</phrase> <phrase role="special">>(</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"><</phrase> <phrase role="identifier">Fn</phrase> <phrase role="special">>(</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"><</phrase> <phrase role="identifier">Fns</phrase> <phrase role="special">>(</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"><</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"><</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">string</phrase> <phrase role="special">></phrase> <phrase role="special">></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">"wavs_third"</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">"wavs_second"</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">"wavs_first"</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">-></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"><<</phrase> <phrase role="string">"wait_all_values_source() => '"</phrase> <phrase role="special"><<</phrase> <phrase role="identifier">value</phrase>
|
|
<phrase role="special"><<</phrase> <phrase role="string">"'"</phrase> <phrase role="special"><<</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"><</phrase><phrase role="identifier">T</phrase><phrase
|
|
role="special">></phrase></code> rather than <code><phrase role="identifier">queue</phrase><phrase
|
|
role="special"><</phrase><phrase role="identifier">T</phrase><phrase
|
|
role="special">></phrase></code>:
|
|
</para>
|
|
<para>
|
|
<programlisting><phrase role="keyword">template</phrase><phrase role="special"><</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">></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"><</phrase> <phrase role="identifier">nchannel</phrase><phrase role="special"><</phrase> <phrase role="identifier">T</phrase> <phrase role="special">></phrase> <phrase role="special">></phrase> <phrase role="identifier">chan</phrase><phrase role="special">,</phrase>
|
|
<phrase role="identifier">Fn</phrase> <phrase role="special">&&</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">-></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"><</phrase>
|
|
<phrase role="identifier">T</phrase> <phrase role="special">></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"><</phrase> <phrase role="identifier">T</phrase> <phrase
|
|
role="special">></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"><</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">></phrase>
|
|
<phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">vector</phrase><phrase role="special"><</phrase> <phrase role="keyword">typename</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">result_of</phrase><phrase role="special"><</phrase> <phrase role="identifier">Fn</phrase><phrase role="special">()</phrase> <phrase role="special">>::</phrase><phrase role="identifier">type</phrase> <phrase role="special">></phrase>
|
|
<phrase role="identifier">wait_all_until_error</phrase><phrase role="special">(</phrase> <phrase role="identifier">Fn</phrase> <phrase role="special">&&</phrase> <phrase role="identifier">function</phrase><phrase role="special">,</phrase> <phrase role="identifier">Fns</phrase> <phrase role="special">&&</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"><</phrase> <phrase role="identifier">Fn</phrase><phrase role="special">()</phrase> <phrase role="special">>::</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"><</phrase> <phrase role="identifier">return_t</phrase> <phrase role="special">></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"><</phrase> <phrase role="identifier">return_t</phrase> <phrase role="special">></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"><</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"><</phrase> <phrase role="identifier">future_t</phrase> <phrase role="special">></phrase> <phrase role="special">></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"><</phrase> <phrase role="identifier">Fn</phrase> <phrase role="special">>(</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"><</phrase> <phrase role="identifier">Fns</phrase> <phrase role="special">>(</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">-></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"><</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">string</phrase> <phrase role="special">></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">"waue_late"</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">"waue_middle"</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">"waue_early"</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">&</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"><<</phrase> <phrase role="string">"wait_all_until_error(fail) threw '"</phrase> <phrase role="special"><<</phrase> <phrase role="identifier">thrown</phrase>
|
|
<phrase role="special"><<</phrase> <phrase role="string">"'"</phrase> <phrase role="special"><<</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"><</phrase>
|
|
<phrase role="identifier">T</phrase> <phrase role="special">></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"><</phrase><phrase role="identifier">T</phrase><phrase
|
|
role="special">></phrase></code> rather than <code><phrase role="identifier">queue</phrase><phrase
|
|
role="special"><</phrase><phrase role="identifier">T</phrase><phrase
|
|
role="special">></phrase></code>.
|
|
</para>
|
|
<para>
|
|
<programlisting><phrase role="comment">// Return a shared_ptr<buffered_channel<future<T>>> 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"><</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">></phrase>
|
|
<phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">shared_ptr</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">buffered_channel</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"><</phrase>
|
|
<phrase role="keyword">typename</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">result_of</phrase><phrase role="special"><</phrase> <phrase role="identifier">Fn</phrase><phrase role="special">()</phrase> <phrase role="special">>::</phrase><phrase role="identifier">type</phrase> <phrase role="special">></phrase> <phrase role="special">></phrase> <phrase role="special">></phrase>
|
|
<phrase role="identifier">wait_all_until_error_source</phrase><phrase role="special">(</phrase> <phrase role="identifier">Fn</phrase> <phrase role="special">&&</phrase> <phrase role="identifier">function</phrase><phrase role="special">,</phrase> <phrase role="identifier">Fns</phrase> <phrase role="special">&&</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"><</phrase> <phrase role="identifier">Fn</phrase><phrase role="special">()</phrase> <phrase role="special">>::</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"><</phrase> <phrase role="identifier">return_t</phrase> <phrase role="special">></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"><</phrase> <phrase role="identifier">future_t</phrase> <phrase role="special">></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"><</phrase> <phrase role="identifier">channel_t</phrase> <phrase role="special">>(</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"><</phrase> <phrase role="identifier">nchannel</phrase><phrase role="special"><</phrase> <phrase role="identifier">future_t</phrase> <phrase role="special">></phrase> <phrase role="special">>(</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"><</phrase> <phrase role="identifier">return_t</phrase> <phrase role="special">>(</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"><</phrase> <phrase role="identifier">Fn</phrase> <phrase role="special">>(</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"><</phrase> <phrase role="identifier">Fns</phrase> <phrase role="special">>(</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"><</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">string</phrase> <phrase role="special">></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"><</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"><</phrase> <phrase role="identifier">future_t</phrase> <phrase role="special">></phrase> <phrase role="special">></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">"wauess_third"</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">"wauess_second"</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">"wauess_first"</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">-></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"><<</phrase> <phrase role="string">"wait_all_until_error_source(success) => '"</phrase> <phrase role="special"><<</phrase> <phrase role="identifier">value</phrase>
|
|
<phrase role="special"><<</phrase> <phrase role="string">"'"</phrase> <phrase role="special"><<</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"><</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">></phrase>
|
|
<phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">vector</phrase><phrase role="special"><</phrase> <phrase role="keyword">typename</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">result_of</phrase><phrase role="special"><</phrase> <phrase role="identifier">Fn</phrase><phrase role="special">()</phrase> <phrase role="special">>::</phrase><phrase role="identifier">type</phrase> <phrase role="special">></phrase>
|
|
<phrase role="identifier">wait_all_collect_errors</phrase><phrase role="special">(</phrase> <phrase role="identifier">Fn</phrase> <phrase role="special">&&</phrase> <phrase role="identifier">function</phrase><phrase role="special">,</phrase> <phrase role="identifier">Fns</phrase> <phrase role="special">&&</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"><</phrase> <phrase role="identifier">Fn</phrase><phrase role="special">()</phrase> <phrase role="special">>::</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"><</phrase> <phrase role="identifier">return_t</phrase> <phrase role="special">></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"><</phrase> <phrase role="identifier">return_t</phrase> <phrase role="special">></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">"wait_all_collect_errors() exceptions"</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"><</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"><</phrase> <phrase role="identifier">future_t</phrase> <phrase role="special">></phrase> <phrase role="special">></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"><</phrase> <phrase role="identifier">Fn</phrase> <phrase role="special">>(</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"><</phrase> <phrase role="identifier">Fns</phrase> <phrase role="special">>(</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">-></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">&</phrase> <phrase role="keyword">operator</phrase><phrase role="special"><<(</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">ostream</phrase><phrase role="special">&</phrase> <phrase role="identifier">out</phrase><phrase role="special">,</phrase> <phrase role="identifier">Data</phrase> <phrase role="keyword">const</phrase><phrase role="special">&</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"><</phrase> <phrase role="identifier">Data</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">"wams_left"</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"><<</phrase> <phrase role="string">"wait_all_members<Data>(success) => "</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">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"><</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">></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">&&</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"><</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">std</phrase><phrase role="special">::</phrase><phrase role="identifier">forward</phrase><phrase role="special"><</phrase> <phrase role="identifier">Fns</phrase> <phrase role="special">>(</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"><</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">></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">&&</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"><></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"><></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"><</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">vector</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="special">>(</phrase>
|
|
<phrase role="special">[](){</phrase> <phrase role="keyword">return</phrase> <phrase role="identifier">sleeper</phrase><phrase role="special">(</phrase><phrase role="string">"wamv_left"</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">"wamv_middle"</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">"wamv_right"</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"><<</phrase> <phrase role="string">"wait_all_members<vector>() =>"</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">&</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"><<</phrase> <phrase role="string">" '"</phrase> <phrase role="special"><<</phrase> <phrase role="identifier">str</phrase> <phrase role="special"><<</phrase> <phrase role="string">"'"</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"><<</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’s main thread because certain
|
|
of their actions will affect its user interface, and the application’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’s main loop <emphasis>itself</emphasis>
|
|
doesn’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’s main loop with <emphasis role="bold">Boost.Fiber</emphasis>’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’s main
|
|
loop. When these fibers have had a turn, control passes to the thread’s main
|
|
fiber, which returns from <code><phrase role="identifier">yield</phrase><phrase
|
|
role="special">()</phrase></code> and resumes the application’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’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’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
|
|
— but that timer’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’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’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’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"><</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">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"><</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">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"><</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">>(</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"><</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="keyword">const</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">(</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">-></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"><</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">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"><</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">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">&</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">&)</phrase> <phrase role="special">=</phrase> <phrase role="keyword">delete</phrase><phrase role="special">;</phrase>
|
|
<phrase role="identifier">service</phrase> <phrase role="special">&</phrase> <phrase role="keyword">operator</phrase><phrase role="special">=(</phrase> <phrase role="identifier">service</phrase> <phrase role="keyword">const</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">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<<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>></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’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>’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"><</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’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">-></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 — 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>’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 — once
|
|
we reach a state in which no fiber is ready —
|
|
that would cause the thread to
|
|
spin.
|
|
</para>
|
|
<para>
|
|
We could, of course, set an Asio timer — again as <link linkend="embedded_main_loop">previously
|
|
discussed</link>. But in this <quote>deeper dive,</quote> we’re trying to
|
|
do a little better.
|
|
</para>
|
|
<para>
|
|
The key to doing better is that since we’re in a fiber, we can run an actual
|
|
loop — 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>
|
|
— 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’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">-></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">-></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"><</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">></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">-></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
|
|
— no matter which — <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’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’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’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">&</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">&){</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’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’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">&){</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’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"><</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">></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"><<</phrase> <phrase role="string">"node: "</phrase> <phrase role="special"><<</phrase> <phrase role="identifier">n</phrase><phrase role="special">.</phrase><phrase role="identifier">id</phrase> <phrase role="special"><<</phrase> <phrase role="string">" | "</phrase><phrase role="special">;</phrase>
|
|
<phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">cout</phrase> <phrase role="special"><<</phrase> <phrase role="string">"cpus: "</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"><<</phrase> <phrase role="identifier">cpu_id</phrase> <phrase role="special"><<</phrase> <phrase role="string">" "</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"><<</phrase> <phrase role="string">"| distance: "</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"><<</phrase> <phrase role="identifier">d</phrase> <phrase role="special"><<</phrase> <phrase role="string">" "</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"><<</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"><<</phrase> <phrase role="string">"done"</phrase> <phrase role="special"><<</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"><</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">></phrase> <phrase role="keyword">const</phrase><phrase role="special">&</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"><</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">>(</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"><</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">></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"><</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">thread</phrase> <phrase role="special">></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">&</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"><</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">>(</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"><</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">></phrase>
|
|
<phrase role="preprocessor">#include</phrase> <phrase role="special"><</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">></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"><</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">uint32_t</phrase> <phrase role="special">></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"><</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">uint32_t</phrase> <phrase role="special">></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"><(</phrase> <phrase role="identifier">node</phrase> <phrase role="keyword">const</phrase><phrase role="special">&,</phrase> <phrase role="identifier">node</phrase> <phrase role="keyword">const</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">vector</phrase><phrase role="special"><</phrase> <phrase role="identifier">node</phrase> <phrase role="special">></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"><</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">></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"><</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">></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"><</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">uint32_t</phrase> <phrase role="special">></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"><</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">uint32_t</phrase> <phrase role="special">></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"><(</phrase> <phrase role="identifier">node</phrase> <phrase role="keyword">const</phrase><phrase role="special">&,</phrase> <phrase role="identifier">node</phrase> <phrase role="keyword">const</phrase><phrase role="special">&)</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"><</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">uint32_t</phrase> <phrase role="special">></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"><</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">uint32_t</phrase> <phrase role="special">></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 > <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<</code>()</link>
|
|
</bridgehead>
|
|
</para>
|
|
<programlisting><phrase role="keyword">bool</phrase> <phrase role="keyword">operator</phrase><phrase role="special"><(</phrase> <phrase role="identifier">node</phrase> <phrase role="keyword">const</phrase><phrase role="special">&</phrase> <phrase role="identifier">lhs</phrase><phrase role="special">,</phrase> <phrase role="identifier">node</phrase> <phrase role="keyword">const</phrase><phrase role="special">&</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"><</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">></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"><</phrase> <phrase role="identifier">node</phrase> <phrase role="special">></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"><</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">></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"><</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">></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"><</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">></phrase> <phrase role="keyword">const</phrase><phrase role="special">&</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">&)</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">&&)</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="keyword">operator</phrase><phrase role="special">=(</phrase> <phrase role="identifier">work_stealing</phrase> <phrase role="keyword">const</phrase><phrase role="special">&)</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="keyword">operator</phrase><phrase role="special">=(</phrase> <phrase role="identifier">work_stealing</phrase> <phrase role="special">&&)</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">&)</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"><</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">></phrase> <phrase role="keyword">const</phrase><phrase role="special">&</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">&</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"><</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">([&</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">&</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">&</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">&</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">&</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">&</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">&</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">&</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"><></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"><</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"><</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"><<<</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">>>>(</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"><</phrase> <phrase role="number">0</phrase> <phrase role="special">>(</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"><</phrase> <phrase role="number">1</phrase> <phrase role="special">>(</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"><<</phrase> <phrase role="string">"f1: GPU computation finished"</phrase> <phrase role="special"><<</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"><</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">></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"><</phrase> <phrase role="identifier">cudaStream_t</phrase><phrase role="special">,</phrase> <phrase role="identifier">cudaError_t</phrase> <phrase role="special">></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"><</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">tuple</phrase><phrase role="special"><</phrase> <phrase role="identifier">cudaStream_t</phrase><phrase role="special">,</phrase> <phrase role="identifier">cudaError_t</phrase> <phrase role="special">></phrase> <phrase role="special">></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"><</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">></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"><</phrase> <phrase role="identifier">cudaStream_t</phrase><phrase role="special">,</phrase> <phrase role="identifier">cudaError_t</phrase> <phrase role="special">></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"><</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">tuple</phrase><phrase role="special"><</phrase> <phrase role="identifier">cudaStream_t</phrase><phrase role="special">,</phrase> <phrase role="identifier">cudaError_t</phrase> <phrase role="special">></phrase> <phrase role="special">></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"><</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">([&</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">&</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">&</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">&</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">&</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">&</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">&</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">&</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"><></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"><</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"><</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"><</phrase> <phrase role="number">0</phrase> <phrase role="special">>(</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"><</phrase> <phrase role="number">1</phrase> <phrase role="special">>(</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"><<</phrase> <phrase role="string">"f1: GPU computation finished"</phrase> <phrase role="special"><<</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"><</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">></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"><</phrase> <phrase role="identifier">hipStream_t</phrase><phrase role="special">,</phrase> <phrase role="identifier">hipError_t</phrase> <phrase role="special">></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"><</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">tuple</phrase><phrase role="special"><</phrase> <phrase role="identifier">hipStream_t</phrase><phrase role="special">,</phrase> <phrase role="identifier">hipError_t</phrase> <phrase role="special">></phrase> <phrase role="special">></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"><</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">></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"><</phrase> <phrase role="identifier">hipStream_t</phrase><phrase role="special">,</phrase> <phrase role="identifier">hipError_t</phrase> <phrase role="special">></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"><</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">tuple</phrase><phrase role="special"><</phrase> <phrase role="identifier">hipStream_t</phrase><phrase role="special">,</phrase> <phrase role="identifier">hipError_t</phrase> <phrase role="special">></phrase> <phrase role="special">></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<>()</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"><</phrase><phrase role="identifier">my_fiber_scheduler</phrase><phrase role="special">>();</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">[&</phrase><phrase role="identifier">mtx</phrase><phrase role="special">,&</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"><</phrase><phrase role="keyword">void</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">buffered_channel</phrase><phrase role="special"><</phrase><phrase role="identifier">task</phrase><phrase role="special">></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">[&</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"><</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">[&</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">[&</phrase><phrase role="identifier">mtx</phrase><phrase role="special">,&</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"><</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">>(</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"><</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">>(</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 µs - 0.06 µs
|
|
</para>
|
|
</entry>
|
|
<entry>
|
|
<para>
|
|
0.42 µs - 0.49 µs
|
|
</para>
|
|
</entry>
|
|
<entry>
|
|
<para>
|
|
0.63 µs - 0.73 µ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 µs - 73 µs
|
|
</para>
|
|
</entry>
|
|
<entry>
|
|
<para>
|
|
52 µs - 73 µs
|
|
</para>
|
|
</entry>
|
|
<entry>
|
|
<para>
|
|
106 µs - 122 µ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’s memory allocation
|
|
algorithm (based on ptmalloc2) as well as Google’s <ulink url="http://goog-perftools.sourceforge.net/doc/tcmalloc.html">TCmalloc</ulink>
|
|
(via linkflags="-ltcmalloc").<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 ’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 µs - 0.09 µs
|
|
</para>
|
|
</entry>
|
|
<entry>
|
|
<para>
|
|
1.69 µs - 1.79 µ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’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’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’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<></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"><</phrase> <phrase role="identifier">priority_props</phrase> <phrase role="special">></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<>, 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">&</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">&</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">&</phrase><phrase role="identifier">c</phrase> <phrase role="special">).</phrase><phrase role="identifier">get_priority</phrase><phrase role="special">()</phrase> <phrase role="special"><</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">&</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">&</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">-></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">-></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">&</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"><</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">mutex</phrase> <phrase role="special">></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"><</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">mutex</phrase> <phrase role="special">></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"><</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">mutex</phrase> <phrase role="special">></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"><</phrase> <phrase role="identifier">priority_scheduler</phrase> <phrase role="special">>();</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"><>()</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"><</phrase> <phrase role="identifier">priority_props</phrase> <phrase role="special">>().</phrase><phrase role="identifier">name</phrase> <phrase role="special">=</phrase> <phrase role="string">"main"</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"><>()</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"><</phrase> <phrase role="keyword">typename</phrase> <phrase role="identifier">Fn</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">launch</phrase><phrase role="special">(</phrase> <phrase role="identifier">Fn</phrase> <phrase role="special">&&</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">&</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">&</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"><</phrase> <phrase role="identifier">priority_props</phrase> <phrase role="special">>()</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"><></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
|
|
— 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>’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’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>
|