2
0
mirror of https://github.com/boostorg/fiber.git synced 2026-02-20 02:32:19 +00:00

Merge branch 'develop' of github.com:olk/boost-fiber into develop

This commit is contained in:
Nat Goodspeed
2016-05-01 10:35:42 -04:00
50 changed files with 3985 additions and 3838 deletions

View File

@@ -34,7 +34,7 @@ The significant points about each of `init_write()` and `init_read()` are:
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.
lets us use the wrapper function[s] return value to deliver relevant data.
[tip [template_link promise] and [template_link future] are your friends here.]
@@ -56,7 +56,7 @@ All we have to do is:
[note 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, [@../../examples/adapt_callbacks.cpp the example program's]
running. In fact, [@../../examples/adapt_callbacks.cpp the example program[s]]
dummy `AsyncAPI` implementation illustrates that: it simulates async I/O by
launching a new thread that sleeps briefly and then calls the relevant
callback.]
@@ -76,7 +76,7 @@ messy boilerplate: normal encapsulation works.
[endsect]
[section Return Errorcode or Data]
Things get a bit more interesting when the async operation's callback passes
Things get a bit more interesting when the async operation[s] callback passes
multiple data items of interest. One approach would be to use `std::pair<>` to
capture both:
@@ -94,9 +94,9 @@ identical to `write_ec()`. You can call it like this:
But a more natural API for a function that obtains data is to return only the
data on success, throwing an exception on error.
As with `write()` above, it's certainly possible to code a `read()` wrapper in
As with `write()` above, it[s] certainly possible to code a `read()` wrapper in
terms of `read_ec()`. But since a given application is unlikely to need both,
let's code `read()` from scratch, leveraging [member_link
let[s] code `read()` from scratch, leveraging [member_link
promise..set_exception]:
[callbacks_read]
@@ -147,9 +147,9 @@ hypothetical `AsyncAPI` asynchronous operations.
Fortunately we need not. Boost.Asio incorporates a mechanism[footnote This
mechanism has been proposed as a conventional way to allow the caller of an
async function to specify completion handling:
arbitrary async function to specify completion handling:
[@http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2014/n4045.pdf N4045].]
by which the caller can customize the notification behavior of every async
by which the caller can customize the notification behavior of any async
operation. Therefore we can construct a ['completion token] which, when passed
to a __boost_asio__ async operation, requests blocking for the calling fiber.
@@ -160,32 +160,25 @@ A typical Asio async function might look something like this:[footnote per [@htt
async_something( ... , CompletionToken&& token)
{
// construct handler_type instance from CompletionToken
handler_type<CompletionToken, ...>::type handler(token);
handler_type<CompletionToken, ...>::type ``[*[`handler(token)]]``;
// construct async_result instance from handler_type
async_result<decltype(handler)> result(handler);
async_result<decltype(handler)> ``[*[`result(handler)]]``;
// ... arrange to call handler on completion ...
// ... initiate actual I/O operation ...
return result.get();
return ``[*[`result.get()]]``;
}
We will engage that mechanism, which is based on specializing Asio's
We will engage that mechanism, which is based on specializing Asio[s]
`handler_type<>` template for the `CompletionToken` type and the signature of
the specific callback. The remainder of this discussion will refer back to
`async_something()` as the Asio async function under consideration.
The implementation described below uses lower-level facilities than `promise`
and `future` for two reasons:
# The `promise` mechanism interacts badly with
[@http://www.boost.org/doc/libs/release/doc/html/boost_asio/reference/io_service/stop.html
`io_service::stop()`]. It produces `broken_promise` exceptions.
# If more than one thread is calling the
[@http://www.boost.org/doc/libs/release/doc/html/boost_asio/reference/io_service/run.html
`io_service::run()`] method, the implementation described below allows
resuming the suspended fiber on whichever thread gets there first with
completion notification. More on this later.
and `future` because the `promise` mechanism interacts badly with
[@http://www.boost.org/doc/libs/release/doc/html/boost_asio/reference/io_service/stop.html
`io_service::stop()`]. It produces `broken_promise` exceptions.
`boost::fibers::asio::yield` is a completion token of this kind. `yield` is an
instance of `yield_t`:
@@ -198,13 +191,10 @@ customization. It can bind a
`boost::system::error_code`]
for use by the actual handler.
In fact there are two canonical instances of `yield_t` [mdash] `yield` and
`yield_hop`:
`yield` is declared as:
[fibers_asio_yield]
We'll get to the differences between these shortly.
Asio customization is engaged by specializing
[@http://www.boost.org/doc/libs/release/doc/html/boost_asio/reference/handler_type.html
`boost::asio::handler_type<>`]
@@ -214,26 +204,25 @@ for `yield_t`:
(There are actually four different specializations in
[@../../examples/asio/detail/yield.hpp detail/yield.hpp],
one for each of the four Asio async callback signatures we expect to have to
support.)
one for each of the four Asio async callback signatures we expect.)
The above directs Asio to use `yield_handler` as the actual handler for an
async operation to which `yield` is passed. There's a generic
async operation to which `yield` is passed. There[s] a generic
`yield_handler<T>` implementation and a `yield_handler<void>` specialization.
Let's start with the `<void>` specialization:
Let[s] start with the `<void>` specialization:
[fibers_asio_yield_handler_void]
`async_something()`, having consulted the `handler_type<>` traits
specialization, instantiates a `yield_handler<void>` to be passed as the
actual callback for the async operation. `yield_handler`'s constructor accepts
actual callback for the async operation. `yield_handler`[s] constructor accepts
the `yield_t` instance (the `yield` object passed to the async function) and
passes it along to `yield_handler_base`:
[fibers_asio_yield_handler_base]
`yield_handler_base` stores a copy of the `yield_t` instance [mdash] which, as
shown above, is only an `error_code` and a `bool`. It also captures the
shown above, contains only an `error_code*`. It also captures the
[class_link context]* for the currently-running fiber by calling [member_link
context..active].
@@ -254,22 +243,22 @@ Naturally that leads us straight to `async_result_base`:
[fibers_asio_async_result_base]
This is how `yield_handler_base::ycomp_` becomes non-null:
`async_result_base`'s constructor injects a pointer back to its own
`async_result_base`[s] constructor injects a pointer back to its own
`yield_completion` member.
Recall that both of the canonical `yield_t` instances `yield` and `yield_hop`
initialize their `error_code*` member `ec_` to `nullptr`. If either of these
instances is passed to `async_something()` (`ec_` is still `nullptr`), the
copy stored in `yield_handler_base` will likewise have null `ec_`.
`async_result_base`'s constructor sets `yield_handler_base`'s `yield_t`'s
`ec_` member to point to its own `error_code` member.
Recall that the canonical `yield_t` instance `yield` initializes its
`error_code*` member `ec_` to `nullptr`. If this instance is passed to
`async_something()` (`ec_` is still `nullptr`), the copy stored in
`yield_handler_base` will likewise have null `ec_`. `async_result_base`[s]
constructor sets `yield_handler_base`[s] `yield_t`[s] `ec_` member to point to
its own `error_code` member.
The stage is now set. `async_something()` initiates the actual async
operation, arranging to call its `yield_handler<void>` instance on completion.
Let's say, for the sake of argument, that the actual async operation's
Let[s] say, for the sake of argument, that the actual async operation[s]
callback has signature `void(error_code)`.
But since it's an async operation, control returns at once to
But since it[s] an async operation, control returns at once to
`async_something()`. `async_something()` calls
`async_result<yield_handler<void>>::get()`, and will return its return value.
@@ -288,57 +277,35 @@ Other fibers will now have a chance to run.
Some time later, the async operation completes. It calls
`yield_handler<void>::operator()(error_code const&)` with an `error_code` indicating
either success or failure. We'll consider both cases.
either success or failure. We[,]ll consider both cases.
`yield_handler<void>` explicitly inherits `operator()(error_code const&)` from
`yield_handler_base`.
`yield_handler_base::operator()(error_code const&)` first sets
`yield_completion::completed_` `true`. This way, if `async_something()`'s
`yield_completion::completed_` `true`. This way, if `async_something()`[s]
async operation completes immediately [mdash] if
`yield_handler_base::operator()` is called even before
`async_result_base::get()` [mdash] the calling fiber will ['not] suspend.
The actual `error_code` produced by the async operation is then stored through
the stored `yield_t::ec_` pointer. If `async_something()`'s caller used (e.g.)
the stored `yield_t::ec_` pointer. If `async_something()`[s] caller used (e.g.)
`yield[my_ec]` to bind a local `error_code` instance, the actual `error_code`
value is stored into the caller's variable. Otherwise, it is stored into
value is stored into the caller[s] variable. Otherwise, it is stored into
`async_result_base::ec_`.
Finally we get to the distinction between `yield` and `yield_hop`.
As described for [member_link context..is_context], a `pinned_context` fiber
is special to the library and must never be passed to [member_link
context..migrate]. We must detect and avoid that case here.
The `yield_t::allow_hop_` `bool` indicates whether `async_something()`'s
caller is willing to allow the running fiber to ["hop] to another thread
(`yield_hop`) or whether s/he insists that the fiber resume on the same thread
(`yield`).
If the caller passed `yield_hop` to `async_something()`, and the running fiber
isn't a `pinned_context`, `yield_handler_base::operator()` passes the
`context` of the original fiber [mdash] the one on which `async_something()`
was called, captured in `yield_handler_base`'s constructor [mdash] to the
current thread's [member_link context..migrate].
If the running application has more than one thread calling
[@http://www.boost.org/doc/libs/release/doc/html/boost_asio/reference/io_service/run.html
`io_service::run()`], that fiber could return from `async_something()` on a
different thread (the one calling `yield_handler_base::operator()`) than the
one on which it entered `async_something()`.
In any case, the fiber is marked as ready to run by passing it to [member_link
If the stored fiber context `yield_handler_base::ctx_` is not already running,
it is marked as ready to run by passing it to [member_link
context..set_ready]. Control then returns from
`yield_handler_base::operator()`: the callback is done.
In due course, the fiber `yield_handler_base::ctx_` is resumed. Control
returns from [member_link context..suspend] to `yield_completion::wait()`,
which returns to `async_result_base::get()`.
In due course, that fiber is resumed. Control returns from [member_link
context..suspend] to `yield_completion::wait()`, which returns to
`async_result_base::get()`.
* If the original caller passed `yield[my_ec]` to `async_something()` to bind
a local `error_code` instance, then `yield_handler_base::operator()` stored
its `error_code` to the caller's `my_ec` instance, leaving
its `error_code` to the caller[s] `my_ec` instance, leaving
`async_result_base::ec_` initialized to success.
* If the original caller passed `yield` to `async_something()` without binding
a local `error_code` variable, then `yield_handler_base::operator()` stored
@@ -349,7 +316,7 @@ which returns to `async_result_base::get()`.
error [mdash] `async_result_base::get()` throws `system_error` with that
`error_code`.
The case in which `async_something()`'s completion callback has signature
The case in which `async_something()`[s] completion callback has signature
`void()` is similar. `yield_handler<void>::operator()()` invokes the machinery
above with a ["success] `error_code`.
@@ -379,10 +346,10 @@ data member.
`async_result<yield_handler<T>>::value_`.
Then it passes control to `yield_handler_base::operator()(error_code)` to deal
with waking (and possibly migrating) the original fiber as described above.
with waking the original fiber as described above.
When `async_result<yield_handler<T>>::get()` resumes, it returns the stored
`value_` to `async_something()` and ultimately to `async_something()`'s
`value_` to `async_something()` and ultimately to `async_something()`[s]
caller.
The case of a callback signature `void(T)` is handled by having

View File

@@ -33,69 +33,75 @@
[def __not_a_fiber__ ['not-a-fiber]]
[def __rendezvous__ ['rendezvous]]
[template mdash[] '''&mdash;''']
[template "[text] '''&#8220;'''[text]'''&#8221;''']
[template superscript[exp] '''<superscript>'''[exp]'''</superscript>''']
[/ important especially for [,] to avoid a space between empty argument
brackets and expansion: the space, if any, becomes part of the expansion!]
[template mdash[]'''&mdash;''']
[template ,[]'''&#8217;''']
[template "[text]'''&#8220;'''[text]'''&#8221;''']
[template superscript[exp]'''<superscript>'''[exp]'''</superscript>''']
[/ "isn[t]" is slightly more readable than "isn[,]t", and so forth]
[template s[][,]s]
[template t[][,]t]
[template class_heading[class_name]
[hding class_[class_name]..Class [`[class_name]]]
]
[template class_link[class_name] [dblink class_[class_name]..[`[class_name]]]]
[template class_link[class_name][dblink class_[class_name]..[`[class_name]]]]
[template template_heading[class_name]
[hding class_[class_name]..Template [`[class_name]<>]]
]
[template template_link[class_name] [dblink class_[class_name]..[`[class_name]<>]]]
[template template_link[class_name][dblink class_[class_name]..[`[class_name]<>]]]
[template member_heading[class_name method_name]
[operator_heading [class_name]..[method_name]..[method_name]]
]
[template member_link[class_name method_name] [operator_link [class_name]..[method_name]..[method_name]]]
[template member_link[class_name method_name][operator_link [class_name]..[method_name]..[method_name]]]
[template operator_heading[class_name method_name method_text]
[hding [class_name]_[method_name]..Member function [`[method_text]]()]
]
[template operator_link[class_name method_name method_text] [dblink [class_name]_[method_name]..[`[class_name]::[method_text]()]]]
[template operator_link[class_name method_name method_text][dblink [class_name]_[method_name]..[`[class_name]::[method_text]()]]]
[template template_member_heading[class_name method_name]
[hding [class_name]_[method_name]..Templated member function [`[method_name]]()]
]
[template template_member_link[class_name method_name] [member_link [class_name]..[method_name]]]
[template template_member_link[class_name method_name][member_link [class_name]..[method_name]]]
[template static_member_heading[class_name method_name]
[hding [class_name]_[method_name]..Static member function [`[method_name]]()]
]
[template static_member_link[class_name method_name] [member_link [class_name]..[method_name]]]
[template static_member_link[class_name method_name][member_link [class_name]..[method_name]]]
[template data_member_heading[class_name member_name]
[hding [class_name]_[member_name]..Data member [`[member_name]]]
]
[template data_member_link[class_name member_name] [dblink [class_name]_[member_name]..[`[class_name]::[member_name]]]]
[template data_member_link[class_name member_name][dblink [class_name]_[member_name]..[`[class_name]::[member_name]]]]
[template function_heading[function_name]
[hding [function_name]..Non-member function [`[function_name]()]]
]
[template function_link[function_name] [dblink [function_name]..[`[function_name]()]]]
[template function_link[function_name][dblink [function_name]..[`[function_name]()]]]
[template function_heading_for[function_name arg]
[hding [function_name]\_for\_[arg]..Non-member function [`[function_name]()]]
]
[template function_link_for[function_name arg] [dblink [function_name]\_for\_[arg]..[`[function_name]()]]]
[template function_link_for[function_name arg][dblink [function_name]\_for\_[arg]..[`[function_name]()]]]
[template ns_function_heading[namespace function_name]
[hding [namespace]_[function_name]..Non-member function [`[namespace]::[function_name]()]]
]
[template ns_function_link[namespace function_name] [dblink [namespace]_[function_name]..[`[namespace]::[function_name]()]]]
[template ns_function_link[namespace function_name][dblink [namespace]_[function_name]..[`[namespace]::[function_name]()]]]
[template anchor[name] '''<anchor id="'''[name]'''"/>''']
[template anchor[name]'''<anchor id="'''[name]'''"/>''']
[template hding[name title]
'''<bridgehead renderas="sect4" id="'''[name]_bridgehead'''">
<phrase id="'''[name]'''"/>
<link linkend="'''[name]'''">'''[title]'''</link>
</bridgehead>'''
]
[template dblink[id text] '''<link linkend="'''[id]'''">'''[text]'''</link>''']
[template `[text] '''<code>'''[text]'''</code>''']
[template dblink[id text]'''<link linkend="'''[id]'''">'''[text]'''</link>''']
[template `[text]'''<code>'''[text]'''</code>''']
[def __allocator_arg_t__ [@http://en.cppreference.com/w/cpp/memory/allocator_arg_t `std::allocator_arg_t`]]
[def __Allocator__ [@http://en.cppreference.com/w/cpp/concept/Allocator `Allocator`]]
@@ -155,12 +161,12 @@
[def __fsp__ [class_link fiber_specific_ptr]]
[def __future_get__ [member_link future..get]]
[def __get_id__ [member_link fiber..get_id]]
[def __io_service__ `boost::asio::io_service`]
[def __io_service__ [@http://www.boost.org/doc/libs/release/doc/html/boost_asio/reference/io_service.html `boost::asio::io_service`]]
[def __join__ [member_link fiber..join]]
[def __migrate__ [member_link context..migrate]]
[def __mutex_lock__ [member_link mutex..lock]]
[def __mutex_try_lock__ [member_link mutex..try_lock]]
[def __run_service__ `boost::fibers::asio::run_service()`]
[def __run_service__ `boost::fibers::asio::run_svc()`]
[def __shared_future_get__ [member_link shared_future..get]]
[def __sleep_for__ [ns_function_link this_fiber..sleep_for]]
[def __sleep_until__ [ns_function_link this_fiber..sleep_until]]

File diff suppressed because it is too large Load Diff

View File

@@ -7,7 +7,7 @@
<link rel="home" href="../index.html" title="Chapter&#160;1.&#160;Fiber">
<link rel="up" href="../index.html" title="Chapter&#160;1.&#160;Fiber">
<link rel="prev" href="migration.html" title="Migrating fibers between threads">
<link rel="next" href="nonblocking.html" title="Integrating Fibers with Nonblocking I/O">
<link rel="next" href="callbacks/overview.html" title="Overview">
</head>
<body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF">
<table cellpadding="2" width="100%"><tr>
@@ -20,964 +20,26 @@
</tr></table>
<hr>
<div class="spirit-nav">
<a accesskey="p" href="migration.html"><img src="../../../../../doc/src/images/prev.png" alt="Prev"></a><a accesskey="u" href="../index.html"><img src="../../../../../doc/src/images/up.png" alt="Up"></a><a accesskey="h" href="../index.html"><img src="../../../../../doc/src/images/home.png" alt="Home"></a><a accesskey="n" href="nonblocking.html"><img src="../../../../../doc/src/images/next.png" alt="Next"></a>
<a accesskey="p" href="migration.html"><img src="../../../../../doc/src/images/prev.png" alt="Prev"></a><a accesskey="u" href="../index.html"><img src="../../../../../doc/src/images/up.png" alt="Up"></a><a accesskey="h" href="../index.html"><img src="../../../../../doc/src/images/home.png" alt="Home"></a><a accesskey="n" href="callbacks/overview.html"><img src="../../../../../doc/src/images/next.png" alt="Next"></a>
</div>
<div class="section">
<div class="titlepage"><div><div><h2 class="title" style="clear: both">
<a name="fiber.callbacks"></a><a name="callbacks"></a><a class="link" href="callbacks.html" title="Integrating Fibers with Asynchronous Callbacks">Integrating Fibers
with Asynchronous Callbacks</a>
</h2></div></div></div>
<h4>
<a name="fiber.callbacks.h0"></a>
<span><a name="fiber.callbacks.overview"></a></span><a class="link" href="callbacks.html#fiber.callbacks.overview">Overview</a>
</h4>
<p>
One of the primary benefits of <span class="bold"><strong>Boost.Fiber</strong></span>
is the ability to use asynchronous operations for efficiency, while at the
same time structuring the calling code <span class="emphasis"><em>as if</em></span> 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 <span class="bold"><strong>Boost.Fiber</strong></span>
with an arbitrary async operation.
</p>
<p>
For purposes of illustration, consider the following hypothetical API:
</p>
<p>
</p>
<pre class="programlisting"><span class="keyword">class</span> <span class="identifier">AsyncAPI</span> <span class="special">{</span>
<span class="keyword">public</span><span class="special">:</span>
<span class="comment">// constructor acquires some resource that can be read and written</span>
<span class="identifier">AsyncAPI</span><span class="special">();</span>
<span class="comment">// callbacks accept an int error code; 0 == success</span>
<span class="keyword">typedef</span> <span class="keyword">int</span> <span class="identifier">errorcode</span><span class="special">;</span>
<span class="comment">// write callback only needs to indicate success or failure</span>
<span class="keyword">void</span> <span class="identifier">init_write</span><span class="special">(</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">string</span> <span class="keyword">const</span><span class="special">&amp;</span> <span class="identifier">data</span><span class="special">,</span>
<span class="identifier">std</span><span class="special">::</span><span class="identifier">function</span><span class="special">&lt;</span> <span class="keyword">void</span><span class="special">(</span> <span class="identifier">errorcode</span><span class="special">)</span> <span class="special">&gt;</span> <span class="keyword">const</span><span class="special">&amp;</span> <span class="identifier">callback</span><span class="special">);</span>
<span class="comment">// read callback needs to accept both errorcode and data</span>
<span class="keyword">void</span> <span class="identifier">init_read</span><span class="special">(</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">function</span><span class="special">&lt;</span> <span class="keyword">void</span><span class="special">(</span> <span class="identifier">errorcode</span><span class="special">,</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">string</span> <span class="keyword">const</span><span class="special">&amp;)</span> <span class="special">&gt;</span> <span class="keyword">const</span><span class="special">&amp;);</span>
<span class="comment">// ... other operations ...</span>
<span class="special">};</span>
</pre>
<p>
</p>
<p>
The significant points about each of <code class="computeroutput"><span class="identifier">init_write</span><span class="special">()</span></code> and <code class="computeroutput"><span class="identifier">init_read</span><span class="special">()</span></code> are:
</p>
<div class="itemizedlist"><ul class="itemizedlist" type="disc">
<li class="listitem">
The <code class="computeroutput"><span class="identifier">AsyncAPI</span></code> method only
initiates the operation. It returns immediately, while the requested operation
is still pending.
</li>
<li class="listitem">
The method accepts a callback. When the operation completes, the callback
is called with relevant parameters (error code, data if applicable).
</li>
</ul></div>
<p>
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.
</p>
<div class="tip"><table border="0" summary="Tip">
<tr>
<td rowspan="2" align="center" valign="top" width="25"><img alt="[Tip]" src="../../../../../doc/src/images/tip.png"></td>
<th align="left">Tip</th>
</tr>
<tr><td align="left" valign="top"><p>
<a class="link" href="synchronization/futures/promise.html#class_promise"> <code class="computeroutput">promise&lt;&gt;</code></a> and <a class="link" href="synchronization/futures/future.html#class_future"> <code class="computeroutput">future&lt;&gt;</code></a> are your friends
here.
</p></td></tr>
</table></div>
<h4>
<a name="fiber.callbacks.h1"></a>
<span><a name="fiber.callbacks.return_errorcode"></a></span><a class="link" href="callbacks.html#fiber.callbacks.return_errorcode">Return
Errorcode</a>
</h4>
<p>
The <code class="computeroutput"><span class="identifier">AsyncAPI</span><span class="special">::</span><span class="identifier">init_write</span><span class="special">()</span></code>
callback passes only an <code class="computeroutput"><span class="identifier">errorcode</span></code>.
If we simply want the blocking wrapper to return that <code class="computeroutput"><span class="identifier">errorcode</span></code>,
this is an extremely straightforward use of <a class="link" href="synchronization/futures/promise.html#class_promise"> <code class="computeroutput">promise&lt;&gt;</code></a> and
<a class="link" href="synchronization/futures/future.html#class_future"> <code class="computeroutput">future&lt;&gt;</code></a>:
</p>
<p>
</p>
<pre class="programlisting"><span class="identifier">AsyncAPI</span><span class="special">::</span><span class="identifier">errorcode</span> <span class="identifier">write_ec</span><span class="special">(</span> <span class="identifier">AsyncAPI</span> <span class="special">&amp;</span> <span class="identifier">api</span><span class="special">,</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">string</span> <span class="keyword">const</span><span class="special">&amp;</span> <span class="identifier">data</span><span class="special">)</span> <span class="special">{</span>
<span class="identifier">boost</span><span class="special">::</span><span class="identifier">fibers</span><span class="special">::</span><span class="identifier">promise</span><span class="special">&lt;</span> <span class="identifier">AsyncAPI</span><span class="special">::</span><span class="identifier">errorcode</span> <span class="special">&gt;</span> <span class="identifier">promise</span><span class="special">;</span>
<span class="identifier">boost</span><span class="special">::</span><span class="identifier">fibers</span><span class="special">::</span><span class="identifier">future</span><span class="special">&lt;</span> <span class="identifier">AsyncAPI</span><span class="special">::</span><span class="identifier">errorcode</span> <span class="special">&gt;</span> <span class="identifier">future</span><span class="special">(</span> <span class="identifier">promise</span><span class="special">.</span><span class="identifier">get_future</span><span class="special">()</span> <span class="special">);</span>
<span class="comment">// In general, even though we block waiting for future::get() and therefore</span>
<span class="comment">// won't destroy 'promise' until promise::set_value() has been called, we</span>
<span class="comment">// are advised that with threads it's possible for ~promise() to be</span>
<span class="comment">// entered before promise::set_value() has returned. While that shouldn't</span>
<span class="comment">// happen with fibers::promise, a robust way to deal with the lifespan</span>
<span class="comment">// issue is to bind 'promise' into our lambda. Since promise is move-only,</span>
<span class="comment">// use initialization capture.</span>
<span class="identifier">api</span><span class="special">.</span><span class="identifier">init_write</span><span class="special">(</span>
<span class="identifier">data</span><span class="special">,</span>
<span class="special">[&amp;</span><span class="identifier">promise</span><span class="special">](</span> <span class="identifier">AsyncAPI</span><span class="special">::</span><span class="identifier">errorcode</span> <span class="identifier">ec</span><span class="special">)</span> <span class="keyword">mutable</span> <span class="special">{</span>
<span class="identifier">promise</span><span class="special">.</span><span class="identifier">set_value</span><span class="special">(</span> <span class="identifier">ec</span><span class="special">);</span>
<span class="special">});</span>
<span class="keyword">return</span> <span class="identifier">future</span><span class="special">.</span><span class="identifier">get</span><span class="special">();</span>
<span class="special">}</span>
</pre>
<p>
</p>
<p>
All we have to do is:
</p>
<div class="orderedlist"><ol class="orderedlist" type="1">
<li class="listitem">
Instantiate a <code class="computeroutput"><span class="identifier">promise</span><span class="special">&lt;&gt;</span></code>
of correct type.
</li>
<li class="listitem">
Obtain its <code class="computeroutput"><span class="identifier">future</span><span class="special">&lt;&gt;</span></code>.
</li>
<li class="listitem">
Arrange for the callback to call <a class="link" href="synchronization/futures/promise.html#promise_set_value"> <code class="computeroutput">promise::set_value()</code></a>.
</li>
<li class="listitem">
Block on <a class="link" href="synchronization/futures/future.html#future_get"> <code class="computeroutput">future::get()</code></a>.
</li>
</ol></div>
<div class="note"><table border="0" summary="Note">
<tr>
<td rowspan="2" align="center" valign="top" width="25"><img alt="[Note]" src="../../../../../doc/src/images/note.png"></td>
<th align="left">Note</th>
</tr>
<tr><td align="left" valign="top"><p>
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, <a href="../../../examples/adapt_callbacks.cpp" target="_top">the example program's</a>
dummy <code class="computeroutput"><span class="identifier">AsyncAPI</span></code> implementation
illustrates that: it simulates async I/O by launching a new thread that sleeps
briefly and then calls the relevant callback.
</p></td></tr>
</table></div>
<h4>
<a name="fiber.callbacks.h2"></a>
<span><a name="fiber.callbacks.success_or_exception"></a></span><a class="link" href="callbacks.html#fiber.callbacks.success_or_exception">Success
or Exception</a>
</h4>
<p>
A wrapper more aligned with modern C++ practice would use an exception, rather
than an <code class="computeroutput"><span class="identifier">errorcode</span></code>, to communicate
failure to its caller. This is straightforward to code in terms of <code class="computeroutput"><span class="identifier">write_ec</span><span class="special">()</span></code>:
</p>
<p>
</p>
<pre class="programlisting"><span class="keyword">void</span> <span class="identifier">write</span><span class="special">(</span> <span class="identifier">AsyncAPI</span> <span class="special">&amp;</span> <span class="identifier">api</span><span class="special">,</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">string</span> <span class="keyword">const</span><span class="special">&amp;</span> <span class="identifier">data</span><span class="special">)</span> <span class="special">{</span>
<span class="identifier">AsyncAPI</span><span class="special">::</span><span class="identifier">errorcode</span> <span class="identifier">ec</span> <span class="special">=</span> <span class="identifier">write_ec</span><span class="special">(</span> <span class="identifier">api</span><span class="special">,</span> <span class="identifier">data</span><span class="special">);</span>
<span class="keyword">if</span> <span class="special">(</span> <span class="identifier">ec</span><span class="special">)</span> <span class="special">{</span>
<span class="keyword">throw</span> <span class="identifier">make_exception</span><span class="special">(</span><span class="string">"write"</span><span class="special">,</span> <span class="identifier">ec</span><span class="special">);</span>
<span class="special">}</span>
<span class="special">}</span>
</pre>
<p>
</p>
<p>
The point is that since each fiber has its own stack, you need not repeat messy
boilerplate: normal encapsulation works.
</p>
<h4>
<a name="fiber.callbacks.h3"></a>
<span><a name="fiber.callbacks.return_errorcode_or_data"></a></span><a class="link" href="callbacks.html#fiber.callbacks.return_errorcode_or_data">Return
Errorcode or Data</a>
</h4>
<p>
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 class="computeroutput"><span class="identifier">std</span><span class="special">::</span><span class="identifier">pair</span><span class="special">&lt;&gt;</span></code> to capture both:
</p>
<p>
</p>
<pre class="programlisting"><span class="identifier">std</span><span class="special">::</span><span class="identifier">pair</span><span class="special">&lt;</span> <span class="identifier">AsyncAPI</span><span class="special">::</span><span class="identifier">errorcode</span><span class="special">,</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">string</span> <span class="special">&gt;</span> <span class="identifier">read_ec</span><span class="special">(</span> <span class="identifier">AsyncAPI</span> <span class="special">&amp;</span> <span class="identifier">api</span><span class="special">)</span> <span class="special">{</span>
<span class="keyword">typedef</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">pair</span><span class="special">&lt;</span> <span class="identifier">AsyncAPI</span><span class="special">::</span><span class="identifier">errorcode</span><span class="special">,</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">string</span> <span class="special">&gt;</span> <span class="identifier">result_pair</span><span class="special">;</span>
<span class="identifier">boost</span><span class="special">::</span><span class="identifier">fibers</span><span class="special">::</span><span class="identifier">promise</span><span class="special">&lt;</span> <span class="identifier">result_pair</span> <span class="special">&gt;</span> <span class="identifier">promise</span><span class="special">;</span>
<span class="identifier">boost</span><span class="special">::</span><span class="identifier">fibers</span><span class="special">::</span><span class="identifier">future</span><span class="special">&lt;</span> <span class="identifier">result_pair</span> <span class="special">&gt;</span> <span class="identifier">future</span><span class="special">(</span> <span class="identifier">promise</span><span class="special">.</span><span class="identifier">get_future</span><span class="special">()</span> <span class="special">);</span>
<span class="comment">// We promise that both 'promise' and 'future' will survive until our</span>
<span class="comment">// lambda has been called.</span>
<span class="identifier">api</span><span class="special">.</span><span class="identifier">init_read</span><span class="special">([&amp;</span><span class="identifier">promise</span><span class="special">](</span> <span class="identifier">AsyncAPI</span><span class="special">::</span><span class="identifier">errorcode</span> <span class="identifier">ec</span><span class="special">,</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">string</span> <span class="keyword">const</span><span class="special">&amp;</span> <span class="identifier">data</span><span class="special">)</span> <span class="keyword">mutable</span> <span class="special">{</span>
<span class="identifier">promise</span><span class="special">.</span><span class="identifier">set_value</span><span class="special">(</span> <span class="identifier">result_pair</span><span class="special">(</span> <span class="identifier">ec</span><span class="special">,</span> <span class="identifier">data</span><span class="special">)</span> <span class="special">);</span>
<span class="special">});</span>
<span class="keyword">return</span> <span class="identifier">future</span><span class="special">.</span><span class="identifier">get</span><span class="special">();</span>
<span class="special">}</span>
</pre>
<p>
</p>
<p>
Once you bundle the interesting data in <code class="computeroutput"><span class="identifier">std</span><span class="special">::</span><span class="identifier">pair</span><span class="special">&lt;&gt;</span></code>,
the code is effectively identical to <code class="computeroutput"><span class="identifier">write_ec</span><span class="special">()</span></code>. You can call it like this:
</p>
<p>
</p>
<pre class="programlisting"><span class="identifier">std</span><span class="special">::</span><span class="identifier">tie</span><span class="special">(</span> <span class="identifier">ec</span><span class="special">,</span> <span class="identifier">data</span><span class="special">)</span> <span class="special">=</span> <span class="identifier">read_ec</span><span class="special">(</span> <span class="identifier">api</span><span class="special">);</span>
</pre>
<p>
</p>
<a name="Data_or_Exception"></a><h4>
<a name="fiber.callbacks.h4"></a>
<span><a name="fiber.callbacks.data_or_exception"></a></span><a class="link" href="callbacks.html#fiber.callbacks.data_or_exception">Data
or Exception</a>
</h4>
<p>
But a more natural API for a function that obtains data is to return only the
data on success, throwing an exception on error.
</p>
<p>
As with <code class="computeroutput"><span class="identifier">write</span><span class="special">()</span></code>
above, it's certainly possible to code a <code class="computeroutput"><span class="identifier">read</span><span class="special">()</span></code> wrapper in terms of <code class="computeroutput"><span class="identifier">read_ec</span><span class="special">()</span></code>. But since a given application is unlikely
to need both, let's code <code class="computeroutput"><span class="identifier">read</span><span class="special">()</span></code> from scratch, leveraging <a class="link" href="synchronization/futures/promise.html#promise_set_exception"> <code class="computeroutput">promise::set_exception()</code></a>:
</p>
<p>
</p>
<pre class="programlisting"><span class="identifier">std</span><span class="special">::</span><span class="identifier">string</span> <span class="identifier">read</span><span class="special">(</span> <span class="identifier">AsyncAPI</span> <span class="special">&amp;</span> <span class="identifier">api</span><span class="special">)</span> <span class="special">{</span>
<span class="identifier">boost</span><span class="special">::</span><span class="identifier">fibers</span><span class="special">::</span><span class="identifier">promise</span><span class="special">&lt;</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">string</span> <span class="special">&gt;</span> <span class="identifier">promise</span><span class="special">;</span>
<span class="identifier">boost</span><span class="special">::</span><span class="identifier">fibers</span><span class="special">::</span><span class="identifier">future</span><span class="special">&lt;</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">string</span> <span class="special">&gt;</span> <span class="identifier">future</span><span class="special">(</span> <span class="identifier">promise</span><span class="special">.</span><span class="identifier">get_future</span><span class="special">()</span> <span class="special">);</span>
<span class="comment">// Both 'promise' and 'future' will survive until our lambda has been</span>
<span class="comment">// called.</span>
<span class="identifier">api</span><span class="special">.</span><span class="identifier">init_read</span><span class="special">([&amp;</span><span class="identifier">promise</span><span class="special">](</span> <span class="identifier">AsyncAPI</span><span class="special">::</span><span class="identifier">errorcode</span> <span class="identifier">ec</span><span class="special">,</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">string</span> <span class="keyword">const</span><span class="special">&amp;</span> <span class="identifier">data</span><span class="special">)</span> <span class="keyword">mutable</span> <span class="special">{</span>
<span class="keyword">if</span> <span class="special">(</span> <span class="special">!</span> <span class="identifier">ec</span><span class="special">)</span> <span class="special">{</span>
<span class="identifier">promise</span><span class="special">.</span><span class="identifier">set_value</span><span class="special">(</span> <span class="identifier">data</span><span class="special">);</span>
<span class="special">}</span> <span class="keyword">else</span> <span class="special">{</span>
<span class="identifier">promise</span><span class="special">.</span><span class="identifier">set_exception</span><span class="special">(</span>
<span class="identifier">std</span><span class="special">::</span><span class="identifier">make_exception_ptr</span><span class="special">(</span>
<span class="identifier">make_exception</span><span class="special">(</span><span class="string">"read"</span><span class="special">,</span> <span class="identifier">ec</span><span class="special">)</span> <span class="special">)</span> <span class="special">);</span>
<span class="special">}</span>
<span class="special">});</span>
<span class="keyword">return</span> <span class="identifier">future</span><span class="special">.</span><span class="identifier">get</span><span class="special">();</span>
<span class="special">}</span>
</pre>
<p>
</p>
<p>
<a class="link" href="synchronization/futures/future.html#future_get"> <code class="computeroutput">future::get()</code></a> will do the right thing, either returning <code class="computeroutput"><span class="identifier">std</span><span class="special">::</span><span class="identifier">string</span></code>
or throwing an exception.
</p>
<h4>
<a name="fiber.callbacks.h5"></a>
<span><a name="fiber.callbacks.success_error_virtual_methods"></a></span><a class="link" href="callbacks.html#fiber.callbacks.success_error_virtual_methods">Success/Error
Virtual Methods</a>
</h4>
<p>
One classic approach to completion notification is to define an abstract base
class with <code class="computeroutput"><span class="identifier">success</span><span class="special">()</span></code>
and <code class="computeroutput"><span class="identifier">error</span><span class="special">()</span></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:
</p>
<p>
</p>
<pre class="programlisting"><span class="comment">// every async operation receives a subclass instance of this abstract base</span>
<span class="comment">// class through which to communicate its result</span>
<span class="keyword">struct</span> <span class="identifier">Response</span> <span class="special">{</span>
<span class="keyword">typedef</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">shared_ptr</span><span class="special">&lt;</span> <span class="identifier">Response</span> <span class="special">&gt;</span> <span class="identifier">ptr</span><span class="special">;</span>
<span class="comment">// called if the operation succeeds</span>
<span class="keyword">virtual</span> <span class="keyword">void</span> <span class="identifier">success</span><span class="special">(</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">string</span> <span class="keyword">const</span><span class="special">&amp;</span> <span class="identifier">data</span><span class="special">)</span> <span class="special">=</span> <span class="number">0</span><span class="special">;</span>
<span class="comment">// called if the operation fails</span>
<span class="keyword">virtual</span> <span class="keyword">void</span> <span class="identifier">error</span><span class="special">(</span> <span class="identifier">AsyncAPIBase</span><span class="special">::</span><span class="identifier">errorcode</span> <span class="identifier">ec</span><span class="special">)</span> <span class="special">=</span> <span class="number">0</span><span class="special">;</span>
<span class="special">};</span>
</pre>
<p>
</p>
<p>
Now the <code class="computeroutput"><span class="identifier">AsyncAPI</span></code> operation
might look more like this:
</p>
<p>
</p>
<pre class="programlisting"><span class="comment">// derive Response subclass, instantiate, pass Response::ptr</span>
<span class="keyword">void</span> <span class="identifier">init_read</span><span class="special">(</span> <span class="identifier">Response</span><span class="special">::</span><span class="identifier">ptr</span><span class="special">);</span>
</pre>
<p>
</p>
<p>
We can address this by writing a one-size-fits-all <code class="computeroutput"><span class="identifier">PromiseResponse</span></code>:
</p>
<p>
</p>
<pre class="programlisting"><span class="keyword">class</span> <span class="identifier">PromiseResponse</span><span class="special">:</span> <span class="keyword">public</span> <span class="identifier">Response</span> <span class="special">{</span>
<span class="keyword">public</span><span class="special">:</span>
<span class="comment">// called if the operation succeeds</span>
<span class="keyword">virtual</span> <span class="keyword">void</span> <span class="identifier">success</span><span class="special">(</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">string</span> <span class="keyword">const</span><span class="special">&amp;</span> <span class="identifier">data</span><span class="special">)</span> <span class="special">{</span>
<span class="identifier">promise_</span><span class="special">.</span><span class="identifier">set_value</span><span class="special">(</span> <span class="identifier">data</span><span class="special">);</span>
<span class="special">}</span>
<span class="comment">// called if the operation fails</span>
<span class="keyword">virtual</span> <span class="keyword">void</span> <span class="identifier">error</span><span class="special">(</span> <span class="identifier">AsyncAPIBase</span><span class="special">::</span><span class="identifier">errorcode</span> <span class="identifier">ec</span><span class="special">)</span> <span class="special">{</span>
<span class="identifier">promise_</span><span class="special">.</span><span class="identifier">set_exception</span><span class="special">(</span>
<span class="identifier">std</span><span class="special">::</span><span class="identifier">make_exception_ptr</span><span class="special">(</span>
<span class="identifier">make_exception</span><span class="special">(</span><span class="string">"read"</span><span class="special">,</span> <span class="identifier">ec</span><span class="special">)</span> <span class="special">)</span> <span class="special">);</span>
<span class="special">}</span>
<span class="identifier">boost</span><span class="special">::</span><span class="identifier">fibers</span><span class="special">::</span><span class="identifier">future</span><span class="special">&lt;</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">string</span> <span class="special">&gt;</span> <span class="identifier">get_future</span><span class="special">()</span> <span class="special">{</span>
<span class="keyword">return</span> <span class="identifier">promise_</span><span class="special">.</span><span class="identifier">get_future</span><span class="special">();</span>
<span class="special">}</span>
<span class="keyword">private</span><span class="special">:</span>
<span class="identifier">boost</span><span class="special">::</span><span class="identifier">fibers</span><span class="special">::</span><span class="identifier">promise</span><span class="special">&lt;</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">string</span> <span class="special">&gt;</span> <span class="identifier">promise_</span><span class="special">;</span>
<span class="special">};</span>
</pre>
<p>
</p>
<p>
Now we can simply obtain the <code class="computeroutput"><span class="identifier">future</span><span class="special">&lt;&gt;</span></code> from that <code class="computeroutput"><span class="identifier">PromiseResponse</span></code>
and wait on its <code class="computeroutput"><span class="identifier">get</span><span class="special">()</span></code>:
</p>
<p>
</p>
<pre class="programlisting"><span class="identifier">std</span><span class="special">::</span><span class="identifier">string</span> <span class="identifier">read</span><span class="special">(</span> <span class="identifier">AsyncAPI</span> <span class="special">&amp;</span> <span class="identifier">api</span><span class="special">)</span> <span class="special">{</span>
<span class="comment">// Because init_read() requires a shared_ptr, we must allocate our</span>
<span class="comment">// ResponsePromise on the heap, even though we know its lifespan.</span>
<span class="keyword">auto</span> <span class="identifier">promisep</span><span class="special">(</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">make_shared</span><span class="special">&lt;</span> <span class="identifier">PromiseResponse</span> <span class="special">&gt;()</span> <span class="special">);</span>
<span class="identifier">boost</span><span class="special">::</span><span class="identifier">fibers</span><span class="special">::</span><span class="identifier">future</span><span class="special">&lt;</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">string</span> <span class="special">&gt;</span> <span class="identifier">future</span><span class="special">(</span> <span class="identifier">promisep</span><span class="special">-&gt;</span><span class="identifier">get_future</span><span class="special">()</span> <span class="special">);</span>
<span class="comment">// Both 'promisep' and 'future' will survive until our lambda has been</span>
<span class="comment">// called.</span>
<span class="identifier">api</span><span class="special">.</span><span class="identifier">init_read</span><span class="special">(</span> <span class="identifier">promisep</span><span class="special">);</span>
<span class="keyword">return</span> <span class="identifier">future</span><span class="special">.</span><span class="identifier">get</span><span class="special">();</span>
<span class="special">}</span>
</pre>
<p>
</p>
<p>
The source code above is found in <a href="../../../examples/adapt_callbacks.cpp" target="_top">adapt_callbacks.cpp</a>
and <a href="../../../examples/adapt_method_calls.cpp" target="_top">adapt_method_calls.cpp</a>.
</p>
<a name="callbacks_asio"></a><h4>
<a name="fiber.callbacks.h6"></a>
<span><a name="fiber.callbacks.then_there_s__ulink_url__http___www_boost_org_doc_libs_release_libs_asio_index_html__boost_asio__ulink_"></a></span><a class="link" href="callbacks.html#fiber.callbacks.then_there_s__ulink_url__http___www_boost_org_doc_libs_release_libs_asio_index_html__boost_asio__ulink_">Then
There's <a href="http://www.boost.org/doc/libs/release/libs/asio/index.html" target="_top">Boost.Asio</a></a>
</h4>
<p>
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 class="computeroutput"><span class="identifier">AsyncAPI</span></code> asynchronous
operations.
</p>
<p>
Fortunately we need not. Boost.Asio incorporates a mechanism<sup>[<a name="fiber.callbacks.f0" href="#ftn.fiber.callbacks.f0" class="footnote">5</a>]</sup> by which the caller can customize the notification behavior of
every async operation. Therefore we can construct a <span class="emphasis"><em>completion token</em></span>
which, when passed to a <a href="http://www.boost.org/doc/libs/release/libs/asio/index.html" target="_top">Boost.Asio</a>
async operation, requests blocking for the calling fiber.
</p>
<p>
A typical Asio async function might look something like this:<sup>[<a name="fiber.callbacks.f1" href="#ftn.fiber.callbacks.f1" class="footnote">6</a>]</sup>
</p>
<pre class="programlisting"><span class="keyword">template</span> <span class="special">&lt;</span> <span class="special">...,</span> <span class="keyword">class</span> <span class="identifier">CompletionToken</span> <span class="special">&gt;</span>
<span class="emphasis"><em>deduced_return_type</em></span>
<span class="identifier">async_something</span><span class="special">(</span> <span class="special">...</span> <span class="special">,</span> <span class="identifier">CompletionToken</span><span class="special">&amp;&amp;</span> <span class="identifier">token</span><span class="special">)</span>
<span class="special">{</span>
<span class="comment">// construct handler_type instance from CompletionToken</span>
<span class="identifier">handler_type</span><span class="special">&lt;</span><span class="identifier">CompletionToken</span><span class="special">,</span> <span class="special">...&gt;::</span><span class="identifier">type</span> <span class="identifier">handler</span><span class="special">(</span><span class="identifier">token</span><span class="special">);</span>
<span class="comment">// construct async_result instance from handler_type</span>
<span class="identifier">async_result</span><span class="special">&lt;</span><span class="keyword">decltype</span><span class="special">(</span><span class="identifier">handler</span><span class="special">)&gt;</span> <span class="identifier">result</span><span class="special">(</span><span class="identifier">handler</span><span class="special">);</span>
<span class="comment">// ... arrange to call handler on completion ...</span>
<span class="comment">// ... initiate actual I/O operation ...</span>
<span class="keyword">return</span> <span class="identifier">result</span><span class="special">.</span><span class="identifier">get</span><span class="special">();</span>
<span class="special">}</span>
</pre>
<p>
We will engage that mechanism, which is based on specializing Asio's <code class="computeroutput"><span class="identifier">handler_type</span><span class="special">&lt;&gt;</span></code>
template for the <code class="computeroutput"><span class="identifier">CompletionToken</span></code>
type and the signature of the specific callback. The remainder of this discussion
will refer back to <code class="computeroutput"><span class="identifier">async_something</span><span class="special">()</span></code> as the Asio async function under consideration.
</p>
<p>
The implementation described below uses lower-level facilities than <code class="computeroutput"><span class="identifier">promise</span></code> and <code class="computeroutput"><span class="identifier">future</span></code>
for two reasons:
</p>
<div class="orderedlist"><ol class="orderedlist" type="1">
<li class="listitem">
The <code class="computeroutput"><span class="identifier">promise</span></code> mechanism interacts
badly with <a href="http://www.boost.org/doc/libs/release/doc/html/boost_asio/reference/io_service/stop.html" target="_top"><code class="computeroutput"><span class="identifier">io_service</span><span class="special">::</span><span class="identifier">stop</span><span class="special">()</span></code></a>.
It produces <code class="computeroutput"><span class="identifier">broken_promise</span></code>
exceptions.
</li>
<li class="listitem">
If more than one thread is calling the <a href="http://www.boost.org/doc/libs/release/doc/html/boost_asio/reference/io_service/run.html" target="_top"><code class="computeroutput"><span class="identifier">io_service</span><span class="special">::</span><span class="identifier">run</span><span class="special">()</span></code></a>
method, the implementation described below allows resuming the suspended
fiber on whichever thread gets there first with completion notification.
More on this later.
</li>
</ol></div>
<p>
<code class="computeroutput"><span class="identifier">boost</span><span class="special">::</span><span class="identifier">fibers</span><span class="special">::</span><span class="identifier">asio</span><span class="special">::</span><span class="identifier">yield</span></code>
is a completion token of this kind. <code class="computeroutput"><span class="identifier">yield</span></code>
is an instance of <code class="computeroutput"><span class="identifier">yield_t</span></code>:
</p>
<p>
</p>
<pre class="programlisting"><span class="keyword">class</span> <span class="identifier">yield_t</span> <span class="special">{</span>
<span class="keyword">public</span><span class="special">:</span>
<span class="identifier">yield_t</span><span class="special">(</span> <span class="keyword">bool</span> <span class="identifier">hop</span><span class="special">)</span> <span class="special">:</span>
<span class="identifier">allow_hop_</span><span class="special">(</span> <span class="identifier">hop</span><span class="special">)</span> <span class="special">{</span>
<span class="special">}</span>
<span class="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.
*/</span>
<span class="identifier">yield_t</span> <span class="keyword">operator</span><span class="special">[](</span> <span class="identifier">boost</span><span class="special">::</span><span class="identifier">system</span><span class="special">::</span><span class="identifier">error_code</span> <span class="special">&amp;</span> <span class="identifier">ec</span><span class="special">)</span> <span class="keyword">const</span> <span class="special">{</span>
<span class="identifier">yield_t</span> <span class="identifier">tmp</span><span class="special">{</span> <span class="special">*</span> <span class="keyword">this</span> <span class="special">};</span>
<span class="identifier">tmp</span><span class="special">.</span><span class="identifier">ec_</span> <span class="special">=</span> <span class="special">&amp;</span> <span class="identifier">ec</span><span class="special">;</span>
<span class="keyword">return</span> <span class="identifier">tmp</span><span class="special">;</span>
<span class="special">}</span>
<span class="comment">//private:</span>
<span class="comment">// ptr to bound error_code instance if any</span>
<span class="identifier">boost</span><span class="special">::</span><span class="identifier">system</span><span class="special">::</span><span class="identifier">error_code</span> <span class="special">*</span> <span class="identifier">ec_</span><span class="special">{</span> <span class="keyword">nullptr</span> <span class="special">};</span>
<span class="comment">// allow calling fiber to "hop" to another thread if it could resume more</span>
<span class="comment">// quickly that way</span>
<span class="keyword">bool</span> <span class="identifier">allow_hop_</span><span class="special">;</span>
<span class="special">};</span>
</pre>
<p>
</p>
<p>
<code class="computeroutput"><span class="identifier">yield_t</span></code> is in fact only a placeholder,
a way to trigger Boost.Asio customization. It can bind a <a href="http://www.boost.org/doc/libs/release/libs/system/doc/reference.html#Class-error_code" target="_top"><code class="computeroutput"><span class="identifier">boost</span><span class="special">::</span><span class="identifier">system</span><span class="special">::</span><span class="identifier">error_code</span></code></a>
for use by the actual handler.
</p>
<p>
In fact there are two canonical instances of <code class="computeroutput"><span class="identifier">yield_t</span></code>
&#8212; <code class="computeroutput"><span class="identifier">yield</span></code> and <code class="computeroutput"><span class="identifier">yield_hop</span></code>:
</p>
<p>
</p>
<pre class="programlisting"><span class="comment">// canonical instance with allow_hop_ == false</span>
<span class="keyword">thread_local</span> <span class="identifier">yield_t</span> <span class="identifier">yield</span><span class="special">{</span> <span class="keyword">false</span> <span class="special">};</span>
<span class="comment">// canonical instance with allow_hop_ == true</span>
<span class="keyword">thread_local</span> <span class="identifier">yield_t</span> <span class="identifier">yield_hop</span><span class="special">{</span> <span class="keyword">true</span> <span class="special">};</span>
</pre>
<p>
</p>
<p>
We'll get to the differences between these shortly.
</p>
<p>
Asio customization is engaged by specializing <a href="http://www.boost.org/doc/libs/release/doc/html/boost_asio/reference/handler_type.html" target="_top"><code class="computeroutput"><span class="identifier">boost</span><span class="special">::</span><span class="identifier">asio</span><span class="special">::</span><span class="identifier">handler_type</span><span class="special">&lt;&gt;</span></code></a> for <code class="computeroutput"><span class="identifier">yield_t</span></code>:
</p>
<p>
</p>
<pre class="programlisting"><span class="comment">// Handler type specialisation for fibers::asio::yield.</span>
<span class="comment">// When 'yield' is passed as a completion handler which accepts only</span>
<span class="comment">// error_code, use yield_handler&lt;void&gt;. yield_handler will take care of the</span>
<span class="comment">// error_code one way or another.</span>
<span class="keyword">template</span><span class="special">&lt;</span> <span class="keyword">typename</span> <span class="identifier">ReturnType</span> <span class="special">&gt;</span>
<span class="keyword">struct</span> <span class="identifier">handler_type</span><span class="special">&lt;</span> <span class="identifier">fibers</span><span class="special">::</span><span class="identifier">asio</span><span class="special">::</span><span class="identifier">yield_t</span><span class="special">,</span> <span class="identifier">ReturnType</span><span class="special">(</span> <span class="identifier">boost</span><span class="special">::</span><span class="identifier">system</span><span class="special">::</span><span class="identifier">error_code</span><span class="special">)</span> <span class="special">&gt;</span>
<span class="special">{</span> <span class="keyword">typedef</span> <span class="identifier">fibers</span><span class="special">::</span><span class="identifier">asio</span><span class="special">::</span><span class="identifier">detail</span><span class="special">::</span><span class="identifier">yield_handler</span><span class="special">&lt;</span> <span class="keyword">void</span> <span class="special">&gt;</span> <span class="identifier">type</span><span class="special">;</span> <span class="special">};</span>
</pre>
<p>
</p>
<p>
(There are actually four different specializations in <a href="../../../examples/asio/detail/yield.hpp" target="_top">detail/yield.hpp</a>,
one for each of the four Asio async callback signatures we expect to have to
support.)
</p>
<p>
The above directs Asio to use <code class="computeroutput"><span class="identifier">yield_handler</span></code>
as the actual handler for an async operation to which <code class="computeroutput"><span class="identifier">yield</span></code>
is passed. There's a generic <code class="computeroutput"><span class="identifier">yield_handler</span><span class="special">&lt;</span><span class="identifier">T</span><span class="special">&gt;</span></code>
implementation and a <code class="computeroutput"><span class="identifier">yield_handler</span><span class="special">&lt;</span><span class="keyword">void</span><span class="special">&gt;</span></code>
specialization. Let's start with the <code class="computeroutput"><span class="special">&lt;</span><span class="keyword">void</span><span class="special">&gt;</span></code> specialization:
</p>
<p>
</p>
<pre class="programlisting"><span class="comment">// yield_handler&lt;void&gt; is like yield_handler&lt;T&gt; without value_. In fact it's</span>
<span class="comment">// just like yield_handler_base.</span>
<span class="keyword">template</span><span class="special">&lt;&gt;</span>
<span class="keyword">class</span> <span class="identifier">yield_handler</span><span class="special">&lt;</span> <span class="keyword">void</span> <span class="special">&gt;:</span> <span class="keyword">public</span> <span class="identifier">yield_handler_base</span> <span class="special">{</span>
<span class="keyword">public</span><span class="special">:</span>
<span class="keyword">explicit</span> <span class="identifier">yield_handler</span><span class="special">(</span> <span class="identifier">yield_t</span> <span class="keyword">const</span><span class="special">&amp;</span> <span class="identifier">y</span><span class="special">)</span> <span class="special">:</span>
<span class="identifier">yield_handler_base</span><span class="special">{</span> <span class="identifier">y</span> <span class="special">}</span> <span class="special">{</span>
<span class="special">}</span>
<span class="comment">// nullary completion callback</span>
<span class="keyword">void</span> <span class="keyword">operator</span><span class="special">()()</span> <span class="special">{</span>
<span class="special">(</span> <span class="special">*</span> <span class="keyword">this</span><span class="special">)(</span> <span class="identifier">boost</span><span class="special">::</span><span class="identifier">system</span><span class="special">::</span><span class="identifier">error_code</span><span class="special">()</span> <span class="special">);</span>
<span class="special">}</span>
<span class="comment">// inherit operator()(error_code) overload from base class</span>
<span class="keyword">using</span> <span class="identifier">yield_handler_base</span><span class="special">::</span><span class="keyword">operator</span><span class="special">();</span>
<span class="special">};</span>
</pre>
<p>
</p>
<p>
<code class="computeroutput"><span class="identifier">async_something</span><span class="special">()</span></code>,
having consulted the <code class="computeroutput"><span class="identifier">handler_type</span><span class="special">&lt;&gt;</span></code> traits specialization, instantiates
a <code class="computeroutput"><span class="identifier">yield_handler</span><span class="special">&lt;</span><span class="keyword">void</span><span class="special">&gt;</span></code> to
be passed as the actual callback for the async operation. <code class="computeroutput"><span class="identifier">yield_handler</span></code>'s
constructor accepts the <code class="computeroutput"><span class="identifier">yield_t</span></code>
instance (the <code class="computeroutput"><span class="identifier">yield</span></code> object
passed to the async function) and passes it along to <code class="computeroutput"><span class="identifier">yield_handler_base</span></code>:
</p>
<p>
</p>
<pre class="programlisting"><span class="comment">// This class encapsulates common elements between yield_handler&lt;T&gt; (capturing</span>
<span class="comment">// a value to return from asio async function) and yield_handler&lt;void&gt; (no</span>
<span class="comment">// such value). See yield_handler&lt;T&gt; and its &lt;void&gt; specialization below. Both</span>
<span class="comment">// yield_handler&lt;T&gt; and yield_handler&lt;void&gt; are passed by value through</span>
<span class="comment">// various layers of asio functions. In other words, they're potentially</span>
<span class="comment">// copied multiple times. So key data such as the yield_completion instance</span>
<span class="comment">// must be stored in our async_result&lt;yield_handler&lt;&gt;&gt; specialization, which</span>
<span class="comment">// should be instantiated only once.</span>
<span class="keyword">class</span> <span class="identifier">yield_handler_base</span> <span class="special">{</span>
<span class="keyword">public</span><span class="special">:</span>
<span class="identifier">yield_handler_base</span><span class="special">(</span> <span class="identifier">yield_t</span> <span class="keyword">const</span><span class="special">&amp;</span> <span class="identifier">y</span><span class="special">)</span> <span class="special">:</span>
<span class="comment">// capture the context* associated with the running fiber</span>
<span class="identifier">ctx_</span><span class="special">{</span> <span class="identifier">boost</span><span class="special">::</span><span class="identifier">fibers</span><span class="special">::</span><span class="identifier">context</span><span class="special">::</span><span class="identifier">active</span><span class="special">()</span> <span class="special">},</span>
<span class="comment">// capture the passed yield_t</span>
<span class="identifier">yt_</span><span class="special">{</span> <span class="identifier">y</span> <span class="special">}</span> <span class="special">{</span>
<span class="special">}</span>
<span class="comment">// completion callback passing only (error_code)</span>
<span class="keyword">void</span> <span class="keyword">operator</span><span class="special">()(</span> <span class="identifier">boost</span><span class="special">::</span><span class="identifier">system</span><span class="special">::</span><span class="identifier">error_code</span> <span class="keyword">const</span><span class="special">&amp;</span> <span class="identifier">ec</span><span class="special">)</span> <span class="special">{</span>
<span class="identifier">BOOST_ASSERT_MSG</span><span class="special">(</span> <span class="identifier">ycomp_</span><span class="special">,</span>
<span class="string">"Must inject yield_completion* "</span>
<span class="string">"before calling yield_handler_base::operator()()"</span><span class="special">);</span>
<span class="identifier">BOOST_ASSERT_MSG</span><span class="special">(</span> <span class="identifier">yt_</span><span class="special">.</span><span class="identifier">ec_</span><span class="special">,</span>
<span class="string">"Must inject boost::system::error_code* "</span>
<span class="string">"before calling yield_handler_base::operator()()"</span><span class="special">);</span>
<span class="comment">// If originating fiber is busy testing completed_ flag, wait until it</span>
<span class="comment">// has observed (! completed_).</span>
<span class="identifier">yield_completion</span><span class="special">::</span><span class="identifier">lock_t</span> <span class="identifier">lk</span><span class="special">{</span> <span class="identifier">ycomp_</span><span class="special">-&gt;</span><span class="identifier">mtx_</span> <span class="special">};</span>
<span class="comment">// Notify a subsequent yield_completion::wait() call that it need not</span>
<span class="comment">// suspend.</span>
<span class="identifier">ycomp_</span><span class="special">-&gt;</span><span class="identifier">completed_</span> <span class="special">=</span> <span class="keyword">true</span><span class="special">;</span>
<span class="comment">// set the error_code bound by yield_t</span>
<span class="special">*</span> <span class="identifier">yt_</span><span class="special">.</span><span class="identifier">ec_</span> <span class="special">=</span> <span class="identifier">ec</span><span class="special">;</span>
<span class="comment">// Are we permitted to wake up the suspended fiber on this thread, the</span>
<span class="comment">// thread that called the completion handler?</span>
<span class="keyword">if</span> <span class="special">(</span> <span class="special">(</span> <span class="special">!</span> <span class="identifier">ctx_</span><span class="special">-&gt;</span><span class="identifier">is_context</span><span class="special">(</span> <span class="identifier">fibers</span><span class="special">::</span><span class="identifier">type</span><span class="special">::</span><span class="identifier">pinned_context</span><span class="special">)</span> <span class="special">)</span> <span class="special">&amp;&amp;</span> <span class="identifier">yt_</span><span class="special">.</span><span class="identifier">allow_hop_</span><span class="special">)</span> <span class="special">{</span>
<span class="comment">// We must not migrate a pinned_context to another thread. If this</span>
<span class="comment">// isn't a pinned_context, and the application passed yield_hop</span>
<span class="comment">// rather than yield, migrate this fiber to the running thread.</span>
<span class="identifier">fibers</span><span class="special">::</span><span class="identifier">context</span><span class="special">::</span><span class="identifier">active</span><span class="special">()-&gt;</span><span class="identifier">migrate</span><span class="special">(</span> <span class="identifier">ctx_</span><span class="special">);</span>
<span class="special">}</span>
<span class="comment">// either way, wake the fiber</span>
<span class="identifier">fibers</span><span class="special">::</span><span class="identifier">context</span><span class="special">::</span><span class="identifier">active</span><span class="special">()-&gt;</span><span class="identifier">set_ready</span><span class="special">(</span> <span class="identifier">ctx_</span><span class="special">);</span>
<span class="special">}</span>
<span class="comment">//private:</span>
<span class="identifier">boost</span><span class="special">::</span><span class="identifier">fibers</span><span class="special">::</span><span class="identifier">context</span> <span class="special">*</span> <span class="identifier">ctx_</span><span class="special">;</span>
<span class="identifier">yield_t</span> <span class="identifier">yt_</span><span class="special">;</span>
<span class="comment">// We depend on this pointer to yield_completion, which will be injected</span>
<span class="comment">// by async_result.</span>
<span class="identifier">yield_completion</span> <span class="special">*</span> <span class="identifier">ycomp_</span><span class="special">{</span> <span class="keyword">nullptr</span> <span class="special">};</span>
<span class="special">};</span>
</pre>
<p>
</p>
<p>
<code class="computeroutput"><span class="identifier">yield_handler_base</span></code> stores a
copy of the <code class="computeroutput"><span class="identifier">yield_t</span></code> instance
&#8212; which, as shown above, is only an <code class="computeroutput"><span class="identifier">error_code</span></code>
and a <code class="computeroutput"><span class="keyword">bool</span></code>. It also captures the
<a class="link" href="scheduling.html#class_context"> <code class="computeroutput">context</code></a>* for the currently-running fiber by calling <a class="link" href="scheduling.html#context_active"> <code class="computeroutput">context::active()</code></a>.
</p>
<p>
You will notice that <code class="computeroutput"><span class="identifier">yield_handler_base</span></code>
has one more data member (<code class="computeroutput"><span class="identifier">ycomp_</span></code>)
that is initialized to <code class="computeroutput"><span class="keyword">nullptr</span></code>
by its constructor &#8212; though its <code class="computeroutput"><span class="keyword">operator</span><span class="special">()()</span></code> method relies on <code class="computeroutput"><span class="identifier">ycomp_</span></code>
being non-null. More on this in a moment.
</p>
<p>
Having constructed the <code class="computeroutput"><span class="identifier">yield_handler</span><span class="special">&lt;</span><span class="keyword">void</span><span class="special">&gt;</span></code>
instance, <code class="computeroutput"><span class="identifier">async_something</span><span class="special">()</span></code>
goes on to construct an <code class="computeroutput"><span class="identifier">async_result</span></code>
specialized for the <code class="computeroutput"><span class="identifier">handler_type</span><span class="special">&lt;&gt;::</span><span class="identifier">type</span></code>:
in this case, <code class="computeroutput"><span class="identifier">async_result</span><span class="special">&lt;</span><span class="identifier">yield_handler</span><span class="special">&lt;</span><span class="keyword">void</span><span class="special">&gt;&gt;</span></code>.
It passes the <code class="computeroutput"><span class="identifier">yield_handler</span><span class="special">&lt;</span><span class="keyword">void</span><span class="special">&gt;</span></code>
instance to the new <code class="computeroutput"><span class="identifier">async_result</span></code>
instance.
</p>
<p>
</p>
<pre class="programlisting"><span class="comment">// Without the need to handle a passed value, our yield_handler&lt;void&gt;</span>
<span class="comment">// specialization is just like async_result_base.</span>
<span class="keyword">template</span><span class="special">&lt;&gt;</span>
<span class="keyword">class</span> <span class="identifier">async_result</span><span class="special">&lt;</span> <span class="identifier">boost</span><span class="special">::</span><span class="identifier">fibers</span><span class="special">::</span><span class="identifier">asio</span><span class="special">::</span><span class="identifier">detail</span><span class="special">::</span><span class="identifier">yield_handler</span><span class="special">&lt;</span> <span class="keyword">void</span> <span class="special">&gt;</span> <span class="special">&gt;</span> <span class="special">:</span>
<span class="keyword">public</span> <span class="identifier">boost</span><span class="special">::</span><span class="identifier">fibers</span><span class="special">::</span><span class="identifier">asio</span><span class="special">::</span><span class="identifier">detail</span><span class="special">::</span><span class="identifier">async_result_base</span> <span class="special">{</span>
<span class="keyword">public</span><span class="special">:</span>
<span class="keyword">typedef</span> <span class="keyword">void</span> <span class="identifier">type</span><span class="special">;</span>
<span class="keyword">explicit</span> <span class="identifier">async_result</span><span class="special">(</span> <span class="identifier">boost</span><span class="special">::</span><span class="identifier">fibers</span><span class="special">::</span><span class="identifier">asio</span><span class="special">::</span><span class="identifier">detail</span><span class="special">::</span><span class="identifier">yield_handler</span><span class="special">&lt;</span> <span class="keyword">void</span> <span class="special">&gt;</span> <span class="special">&amp;</span> <span class="identifier">h</span><span class="special">):</span>
<span class="identifier">boost</span><span class="special">::</span><span class="identifier">fibers</span><span class="special">::</span><span class="identifier">asio</span><span class="special">::</span><span class="identifier">detail</span><span class="special">::</span><span class="identifier">async_result_base</span><span class="special">{</span> <span class="identifier">h</span> <span class="special">}</span> <span class="special">{</span>
<span class="special">}</span>
<span class="special">};</span>
</pre>
<p>
</p>
<p>
Naturally that leads us straight to <code class="computeroutput"><span class="identifier">async_result_base</span></code>:
</p>
<p>
</p>
<pre class="programlisting"><span class="comment">// Factor out commonality between async_result&lt;yield_handler&lt;T&gt;&gt; and</span>
<span class="comment">// async_result&lt;yield_handler&lt;void&gt;&gt;</span>
<span class="keyword">class</span> <span class="identifier">async_result_base</span> <span class="special">{</span>
<span class="keyword">public</span><span class="special">:</span>
<span class="keyword">explicit</span> <span class="identifier">async_result_base</span><span class="special">(</span> <span class="identifier">yield_handler_base</span> <span class="special">&amp;</span> <span class="identifier">h</span><span class="special">)</span> <span class="special">{</span>
<span class="comment">// Inject ptr to our yield_completion instance into this</span>
<span class="comment">// yield_handler&lt;&gt;.</span>
<span class="identifier">h</span><span class="special">.</span><span class="identifier">ycomp_</span> <span class="special">=</span> <span class="special">&amp;</span> <span class="keyword">this</span><span class="special">-&gt;</span><span class="identifier">ycomp_</span><span class="special">;</span>
<span class="comment">// if yield_t didn't bind an error_code, make yield_handler_base's</span>
<span class="comment">// error_code* point to an error_code local to this object so</span>
<span class="comment">// yield_handler_base::operator() can unconditionally store through</span>
<span class="comment">// its error_code*</span>
<span class="keyword">if</span> <span class="special">(</span> <span class="special">!</span> <span class="identifier">h</span><span class="special">.</span><span class="identifier">yt_</span><span class="special">.</span><span class="identifier">ec_</span><span class="special">)</span> <span class="special">{</span>
<span class="identifier">h</span><span class="special">.</span><span class="identifier">yt_</span><span class="special">.</span><span class="identifier">ec_</span> <span class="special">=</span> <span class="special">&amp;</span> <span class="identifier">ec_</span><span class="special">;</span>
<span class="special">}</span>
<span class="special">}</span>
<span class="keyword">void</span> <span class="identifier">get</span><span class="special">()</span> <span class="special">{</span>
<span class="comment">// Unless yield_handler_base::operator() has already been called,</span>
<span class="comment">// suspend the calling fiber until that call.</span>
<span class="identifier">ycomp_</span><span class="special">.</span><span class="identifier">wait</span><span class="special">();</span>
<span class="comment">// The only way our own ec_ member could have a non-default value is</span>
<span class="comment">// if our yield_handler did not have a bound error_code AND the</span>
<span class="comment">// completion callback passed a non-default error_code.</span>
<span class="keyword">if</span> <span class="special">(</span> <span class="identifier">ec_</span><span class="special">)</span> <span class="special">{</span>
<span class="identifier">throw_exception</span><span class="special">(</span> <span class="identifier">boost</span><span class="special">::</span><span class="identifier">system</span><span class="special">::</span><span class="identifier">system_error</span><span class="special">{</span> <span class="identifier">ec_</span> <span class="special">}</span> <span class="special">);</span>
<span class="special">}</span>
<span class="identifier">boost</span><span class="special">::</span><span class="identifier">this_fiber</span><span class="special">::</span><span class="identifier">interruption_point</span><span class="special">();</span>
<span class="special">}</span>
<span class="keyword">private</span><span class="special">:</span>
<span class="comment">// If yield_t does not bind an error_code instance, store into here.</span>
<span class="identifier">boost</span><span class="special">::</span><span class="identifier">system</span><span class="special">::</span><span class="identifier">error_code</span> <span class="identifier">ec_</span><span class="special">{};</span>
<span class="comment">// async_result_base owns the yield_completion because, unlike</span>
<span class="comment">// yield_handler&lt;&gt;, async_result&lt;&gt; is only instantiated once.</span>
<span class="identifier">yield_completion</span> <span class="identifier">ycomp_</span><span class="special">{};</span>
<span class="special">};</span>
</pre>
<p>
</p>
<p>
This is how <code class="computeroutput"><span class="identifier">yield_handler_base</span><span class="special">::</span><span class="identifier">ycomp_</span></code>
becomes non-null: <code class="computeroutput"><span class="identifier">async_result_base</span></code>'s
constructor injects a pointer back to its own <code class="computeroutput"><span class="identifier">yield_completion</span></code>
member.
</p>
<p>
Recall that both of the canonical <code class="computeroutput"><span class="identifier">yield_t</span></code>
instances <code class="computeroutput"><span class="identifier">yield</span></code> and <code class="computeroutput"><span class="identifier">yield_hop</span></code> initialize their <code class="computeroutput"><span class="identifier">error_code</span><span class="special">*</span></code>
member <code class="computeroutput"><span class="identifier">ec_</span></code> to <code class="computeroutput"><span class="keyword">nullptr</span></code>. If either of these instances is passed
to <code class="computeroutput"><span class="identifier">async_something</span><span class="special">()</span></code>
(<code class="computeroutput"><span class="identifier">ec_</span></code> is still <code class="computeroutput"><span class="keyword">nullptr</span></code>), the copy stored in <code class="computeroutput"><span class="identifier">yield_handler_base</span></code>
will likewise have null <code class="computeroutput"><span class="identifier">ec_</span></code>.
<code class="computeroutput"><span class="identifier">async_result_base</span></code>'s constructor
sets <code class="computeroutput"><span class="identifier">yield_handler_base</span></code>'s
<code class="computeroutput"><span class="identifier">yield_t</span></code>'s <code class="computeroutput"><span class="identifier">ec_</span></code>
member to point to its own <code class="computeroutput"><span class="identifier">error_code</span></code>
member.
</p>
<p>
The stage is now set. <code class="computeroutput"><span class="identifier">async_something</span><span class="special">()</span></code> initiates the actual async operation, arranging
to call its <code class="computeroutput"><span class="identifier">yield_handler</span><span class="special">&lt;</span><span class="keyword">void</span><span class="special">&gt;</span></code> instance
on completion. Let's say, for the sake of argument, that the actual async operation's
callback has signature <code class="computeroutput"><span class="keyword">void</span><span class="special">(</span><span class="identifier">error_code</span><span class="special">)</span></code>.
</p>
<p>
But since it's an async operation, control returns at once to <code class="computeroutput"><span class="identifier">async_something</span><span class="special">()</span></code>.
<code class="computeroutput"><span class="identifier">async_something</span><span class="special">()</span></code>
calls <code class="computeroutput"><span class="identifier">async_result</span><span class="special">&lt;</span><span class="identifier">yield_handler</span><span class="special">&lt;</span><span class="keyword">void</span><span class="special">&gt;&gt;::</span><span class="identifier">get</span><span class="special">()</span></code>, and
will return its return value.
</p>
<p>
<code class="computeroutput"><span class="identifier">async_result</span><span class="special">&lt;</span><span class="identifier">yield_handler</span><span class="special">&lt;</span><span class="keyword">void</span><span class="special">&gt;&gt;::</span><span class="identifier">get</span><span class="special">()</span></code> inherits
<code class="computeroutput"><span class="identifier">async_result_base</span><span class="special">::</span><span class="identifier">get</span><span class="special">()</span></code>.
</p>
<p>
<code class="computeroutput"><span class="identifier">async_result_base</span><span class="special">::</span><span class="identifier">get</span><span class="special">()</span></code> immediately
calls <code class="computeroutput"><span class="identifier">yield_completion</span><span class="special">::</span><span class="identifier">wait</span><span class="special">()</span></code>.
</p>
<p>
</p>
<pre class="programlisting"><span class="comment">// Bundle a completion bool flag with a spinlock to protect it.</span>
<span class="keyword">struct</span> <span class="identifier">yield_completion</span> <span class="special">{</span>
<span class="keyword">typedef</span> <span class="identifier">fibers</span><span class="special">::</span><span class="identifier">detail</span><span class="special">::</span><span class="identifier">spinlock</span> <span class="identifier">mutex_t</span><span class="special">;</span>
<span class="keyword">typedef</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">unique_lock</span><span class="special">&lt;</span> <span class="identifier">mutex_t</span> <span class="special">&gt;</span> <span class="identifier">lock_t</span><span class="special">;</span>
<span class="identifier">mutex_t</span> <span class="identifier">mtx_</span><span class="special">{};</span>
<span class="keyword">bool</span> <span class="identifier">completed_</span><span class="special">{</span> <span class="keyword">false</span> <span class="special">};</span>
<span class="keyword">void</span> <span class="identifier">wait</span><span class="special">()</span> <span class="special">{</span>
<span class="comment">// yield_handler_base::operator()() will set completed_ true and</span>
<span class="comment">// attempt to wake a suspended fiber. It would be Bad if that call</span>
<span class="comment">// happened between our detecting (! completed_) and suspending.</span>
<span class="identifier">lock_t</span> <span class="identifier">lk</span><span class="special">{</span> <span class="identifier">mtx_</span> <span class="special">};</span>
<span class="comment">// If completed_ is already set, we're done here: don't suspend.</span>
<span class="keyword">if</span> <span class="special">(</span> <span class="special">!</span> <span class="identifier">completed_</span><span class="special">)</span> <span class="special">{</span>
<span class="comment">// suspend(unique_lock&lt;spinlock&gt;) unlocks the lock in the act of</span>
<span class="comment">// resuming another fiber</span>
<span class="identifier">fibers</span><span class="special">::</span><span class="identifier">context</span><span class="special">::</span><span class="identifier">active</span><span class="special">()-&gt;</span><span class="identifier">suspend</span><span class="special">(</span> <span class="identifier">lk</span><span class="special">);</span>
<span class="special">}</span>
<span class="special">}</span>
<span class="special">};</span>
</pre>
<p>
</p>
<p>
Supposing that the pending async operation has not yet completed, <code class="computeroutput"><span class="identifier">yield_completion</span><span class="special">::</span><span class="identifier">completed_</span></code> will still be <code class="computeroutput"><span class="keyword">false</span></code>,
and <code class="computeroutput"><span class="identifier">wait</span><span class="special">()</span></code>
will call <a class="link" href="scheduling.html#context_suspend"> <code class="computeroutput">context::suspend()</code></a> on the currently-running fiber.
</p>
<p>
Other fibers will now have a chance to run.
</p>
<p>
Some time later, the async operation completes. It calls <code class="computeroutput"><span class="identifier">yield_handler</span><span class="special">&lt;</span><span class="keyword">void</span><span class="special">&gt;::</span><span class="keyword">operator</span><span class="special">()(</span><span class="identifier">error_code</span> <span class="keyword">const</span><span class="special">&amp;)</span></code> with an <code class="computeroutput"><span class="identifier">error_code</span></code>
indicating either success or failure. We'll consider both cases.
</p>
<p>
<code class="computeroutput"><span class="identifier">yield_handler</span><span class="special">&lt;</span><span class="keyword">void</span><span class="special">&gt;</span></code> explicitly
inherits <code class="computeroutput"><span class="keyword">operator</span><span class="special">()(</span><span class="identifier">error_code</span> <span class="keyword">const</span><span class="special">&amp;)</span></code> from <code class="computeroutput"><span class="identifier">yield_handler_base</span></code>.
</p>
<p>
<code class="computeroutput"><span class="identifier">yield_handler_base</span><span class="special">::</span><span class="keyword">operator</span><span class="special">()(</span><span class="identifier">error_code</span> <span class="keyword">const</span><span class="special">&amp;)</span></code> first sets <code class="computeroutput"><span class="identifier">yield_completion</span><span class="special">::</span><span class="identifier">completed_</span></code>
<code class="computeroutput"><span class="keyword">true</span></code>. This way, if <code class="computeroutput"><span class="identifier">async_something</span><span class="special">()</span></code>'s
async operation completes immediately &#8212; if <code class="computeroutput"><span class="identifier">yield_handler_base</span><span class="special">::</span><span class="keyword">operator</span><span class="special">()</span></code>
is called even before <code class="computeroutput"><span class="identifier">async_result_base</span><span class="special">::</span><span class="identifier">get</span><span class="special">()</span></code>
&#8212; the calling fiber will <span class="emphasis"><em>not</em></span> suspend.
</p>
<p>
The actual <code class="computeroutput"><span class="identifier">error_code</span></code> produced
by the async operation is then stored through the stored <code class="computeroutput"><span class="identifier">yield_t</span><span class="special">::</span><span class="identifier">ec_</span></code> pointer.
If <code class="computeroutput"><span class="identifier">async_something</span><span class="special">()</span></code>'s
caller used (e.g.) <code class="computeroutput"><span class="identifier">yield</span><span class="special">[</span><span class="identifier">my_ec</span><span class="special">]</span></code> to
bind a local <code class="computeroutput"><span class="identifier">error_code</span></code> instance,
the actual <code class="computeroutput"><span class="identifier">error_code</span></code> value
is stored into the caller's variable. Otherwise, it is stored into <code class="computeroutput"><span class="identifier">async_result_base</span><span class="special">::</span><span class="identifier">ec_</span></code>.
</p>
<p>
Finally we get to the distinction between <code class="computeroutput"><span class="identifier">yield</span></code>
and <code class="computeroutput"><span class="identifier">yield_hop</span></code>.
</p>
<p>
As described for <a class="link" href="scheduling.html#context_is_context"> <code class="computeroutput">context::is_context()</code></a>, a <code class="computeroutput"><span class="identifier">pinned_context</span></code>
fiber is special to the library and must never be passed to <a class="link" href="scheduling.html#context_migrate"> <code class="computeroutput">context::migrate()</code></a>.
We must detect and avoid that case here.
</p>
<p>
The <code class="computeroutput"><span class="identifier">yield_t</span><span class="special">::</span><span class="identifier">allow_hop_</span></code> <code class="computeroutput"><span class="keyword">bool</span></code>
indicates whether <code class="computeroutput"><span class="identifier">async_something</span><span class="special">()</span></code>'s caller is willing to allow the running
fiber to <span class="quote">&#8220;<span class="quote">hop</span>&#8221;</span> to another thread (<code class="computeroutput"><span class="identifier">yield_hop</span></code>)
or whether s/he insists that the fiber resume on the same thread (<code class="computeroutput"><span class="identifier">yield</span></code>).
</p>
<p>
If the caller passed <code class="computeroutput"><span class="identifier">yield_hop</span></code>
to <code class="computeroutput"><span class="identifier">async_something</span><span class="special">()</span></code>,
and the running fiber isn't a <code class="computeroutput"><span class="identifier">pinned_context</span></code>,
<code class="computeroutput"><span class="identifier">yield_handler_base</span><span class="special">::</span><span class="keyword">operator</span><span class="special">()</span></code> passes
the <code class="computeroutput"><span class="identifier">context</span></code> of the original
fiber &#8212; the one on which <code class="computeroutput"><span class="identifier">async_something</span><span class="special">()</span></code> was called, captured in <code class="computeroutput"><span class="identifier">yield_handler_base</span></code>'s
constructor &#8212; to the current thread's <a class="link" href="scheduling.html#context_migrate"> <code class="computeroutput">context::migrate()</code></a>.
</p>
<p>
If the running application has more than one thread calling <a href="http://www.boost.org/doc/libs/release/doc/html/boost_asio/reference/io_service/run.html" target="_top"><code class="computeroutput"><span class="identifier">io_service</span><span class="special">::</span><span class="identifier">run</span><span class="special">()</span></code></a>,
that fiber could return from <code class="computeroutput"><span class="identifier">async_something</span><span class="special">()</span></code> on a different thread (the one calling <code class="computeroutput"><span class="identifier">yield_handler_base</span><span class="special">::</span><span class="keyword">operator</span><span class="special">()</span></code>)
than the one on which it entered <code class="computeroutput"><span class="identifier">async_something</span><span class="special">()</span></code>.
</p>
<p>
In any case, the fiber is marked as ready to run by passing it to <a class="link" href="scheduling.html#context_set_ready"> <code class="computeroutput">context::set_ready()</code></a>.
Control then returns from <code class="computeroutput"><span class="identifier">yield_handler_base</span><span class="special">::</span><span class="keyword">operator</span><span class="special">()</span></code>:
the callback is done.
</p>
<p>
In due course, the fiber <code class="computeroutput"><span class="identifier">yield_handler_base</span><span class="special">::</span><span class="identifier">ctx_</span></code> is
resumed. Control returns from <a class="link" href="scheduling.html#context_suspend"> <code class="computeroutput">context::suspend()</code></a> to <code class="computeroutput"><span class="identifier">yield_completion</span><span class="special">::</span><span class="identifier">wait</span><span class="special">()</span></code>, which
returns to <code class="computeroutput"><span class="identifier">async_result_base</span><span class="special">::</span><span class="identifier">get</span><span class="special">()</span></code>.
</p>
<div class="itemizedlist"><ul class="itemizedlist" type="disc">
<li class="listitem">
If the original caller passed <code class="computeroutput"><span class="identifier">yield</span><span class="special">[</span><span class="identifier">my_ec</span><span class="special">]</span></code> to <code class="computeroutput"><span class="identifier">async_something</span><span class="special">()</span></code> to bind a local <code class="computeroutput"><span class="identifier">error_code</span></code>
instance, then <code class="computeroutput"><span class="identifier">yield_handler_base</span><span class="special">::</span><span class="keyword">operator</span><span class="special">()</span></code> stored its <code class="computeroutput"><span class="identifier">error_code</span></code>
to the caller's <code class="computeroutput"><span class="identifier">my_ec</span></code> instance,
leaving <code class="computeroutput"><span class="identifier">async_result_base</span><span class="special">::</span><span class="identifier">ec_</span></code>
initialized to success.
</li>
<li class="listitem">
If the original caller passed <code class="computeroutput"><span class="identifier">yield</span></code>
to <code class="computeroutput"><span class="identifier">async_something</span><span class="special">()</span></code>
without binding a local <code class="computeroutput"><span class="identifier">error_code</span></code>
variable, then <code class="computeroutput"><span class="identifier">yield_handler_base</span><span class="special">::</span><span class="keyword">operator</span><span class="special">()</span></code> stored its <code class="computeroutput"><span class="identifier">error_code</span></code>
into <code class="computeroutput"><span class="identifier">async_result_base</span><span class="special">::</span><span class="identifier">ec_</span></code>.
If in fact that <code class="computeroutput"><span class="identifier">error_code</span></code>
is success, then all is well.
</li>
<li class="listitem">
Otherwise &#8212; the original caller did not bind a local <code class="computeroutput"><span class="identifier">error_code</span></code>
and <code class="computeroutput"><span class="identifier">yield_handler_base</span><span class="special">::</span><span class="keyword">operator</span><span class="special">()</span></code> was called with an <code class="computeroutput"><span class="identifier">error_code</span></code>
indicating error &#8212; <code class="computeroutput"><span class="identifier">async_result_base</span><span class="special">::</span><span class="identifier">get</span><span class="special">()</span></code> throws <code class="computeroutput"><span class="identifier">system_error</span></code>
with that <code class="computeroutput"><span class="identifier">error_code</span></code>.
</li>
</ul></div>
<p>
The case in which <code class="computeroutput"><span class="identifier">async_something</span><span class="special">()</span></code>'s completion callback has signature <code class="computeroutput"><span class="keyword">void</span><span class="special">()</span></code> is similar.
<code class="computeroutput"><span class="identifier">yield_handler</span><span class="special">&lt;</span><span class="keyword">void</span><span class="special">&gt;::</span><span class="keyword">operator</span><span class="special">()()</span></code> invokes the machinery above with a <span class="quote">&#8220;<span class="quote">success</span>&#8221;</span>
<code class="computeroutput"><span class="identifier">error_code</span></code>.
</p>
<p>
A completion callback with signature <code class="computeroutput"><span class="keyword">void</span><span class="special">(</span><span class="identifier">error_code</span><span class="special">,</span> <span class="identifier">T</span><span class="special">)</span></code>
(that is: in addition to <code class="computeroutput"><span class="identifier">error_code</span></code>,
callback receives some data item) is handled somewhat differently. For this
kind of signature, <code class="computeroutput"><span class="identifier">handler_type</span><span class="special">&lt;&gt;::</span><span class="identifier">type</span></code>
specifies <code class="computeroutput"><span class="identifier">yield_handler</span><span class="special">&lt;</span><span class="identifier">T</span><span class="special">&gt;</span></code> (for
<code class="computeroutput"><span class="identifier">T</span></code> other than <code class="computeroutput"><span class="keyword">void</span></code>).
</p>
<p>
A <code class="computeroutput"><span class="identifier">yield_handler</span><span class="special">&lt;</span><span class="identifier">T</span><span class="special">&gt;</span></code> reserves
a <code class="computeroutput"><span class="identifier">value_</span></code> pointer to a value
of type <code class="computeroutput"><span class="identifier">T</span></code>:
</p>
<p>
</p>
<pre class="programlisting"><span class="comment">// asio uses handler_type&lt;completion token type, signature&gt;::type to decide</span>
<span class="comment">// what to instantiate as the actual handler. Below, we specialize</span>
<span class="comment">// handler_type&lt; yield_t, ... &gt; to indicate yield_handler&lt;&gt;. So when you pass</span>
<span class="comment">// an instance of yield_t as an asio completion token, asio selects</span>
<span class="comment">// yield_handler&lt;&gt; as the actual handler class.</span>
<span class="keyword">template</span><span class="special">&lt;</span> <span class="keyword">typename</span> <span class="identifier">T</span> <span class="special">&gt;</span>
<span class="keyword">class</span> <span class="identifier">yield_handler</span><span class="special">:</span> <span class="keyword">public</span> <span class="identifier">yield_handler_base</span> <span class="special">{</span>
<span class="keyword">public</span><span class="special">:</span>
<span class="comment">// asio passes the completion token to the handler constructor</span>
<span class="keyword">explicit</span> <span class="identifier">yield_handler</span><span class="special">(</span> <span class="identifier">yield_t</span> <span class="keyword">const</span><span class="special">&amp;</span> <span class="identifier">y</span><span class="special">)</span> <span class="special">:</span>
<span class="identifier">yield_handler_base</span><span class="special">{</span> <span class="identifier">y</span> <span class="special">}</span> <span class="special">{</span>
<span class="special">}</span>
<span class="comment">// completion callback passing only value (T)</span>
<span class="keyword">void</span> <span class="keyword">operator</span><span class="special">()(</span> <span class="identifier">T</span> <span class="identifier">t</span><span class="special">)</span> <span class="special">{</span>
<span class="comment">// just like callback passing success error_code</span>
<span class="special">(*</span><span class="keyword">this</span><span class="special">)(</span> <span class="identifier">boost</span><span class="special">::</span><span class="identifier">system</span><span class="special">::</span><span class="identifier">error_code</span><span class="special">(),</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">move</span><span class="special">(</span><span class="identifier">t</span><span class="special">)</span> <span class="special">);</span>
<span class="special">}</span>
<span class="comment">// completion callback passing (error_code, T)</span>
<span class="keyword">void</span> <span class="keyword">operator</span><span class="special">()(</span> <span class="identifier">boost</span><span class="special">::</span><span class="identifier">system</span><span class="special">::</span><span class="identifier">error_code</span> <span class="keyword">const</span><span class="special">&amp;</span> <span class="identifier">ec</span><span class="special">,</span> <span class="identifier">T</span> <span class="identifier">t</span><span class="special">)</span> <span class="special">{</span>
<span class="identifier">BOOST_ASSERT_MSG</span><span class="special">(</span> <span class="identifier">value_</span><span class="special">,</span>
<span class="string">"Must inject value ptr "</span>
<span class="string">"before caling yield_handler&lt;T&gt;::operator()()"</span><span class="special">);</span>
<span class="comment">// move the value to async_result&lt;&gt; instance BEFORE waking up a</span>
<span class="comment">// suspended fiber</span>
<span class="special">*</span> <span class="identifier">value_</span> <span class="special">=</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">move</span><span class="special">(</span> <span class="identifier">t</span><span class="special">);</span>
<span class="comment">// forward the call to base-class completion handler</span>
<span class="identifier">yield_handler_base</span><span class="special">::</span><span class="keyword">operator</span><span class="special">()(</span> <span class="identifier">ec</span><span class="special">);</span>
<span class="special">}</span>
<span class="comment">//private:</span>
<span class="comment">// pointer to destination for eventual value</span>
<span class="comment">// this must be injected by async_result before operator()() is called</span>
<span class="identifier">T</span> <span class="special">*</span> <span class="identifier">value_</span><span class="special">{</span> <span class="keyword">nullptr</span> <span class="special">};</span>
<span class="special">};</span>
</pre>
<p>
</p>
<p>
This pointer is initialized to <code class="computeroutput"><span class="keyword">nullptr</span></code>.
</p>
<p>
When <code class="computeroutput"><span class="identifier">async_something</span><span class="special">()</span></code>
instantiates <code class="computeroutput"><span class="identifier">async_result</span><span class="special">&lt;</span><span class="identifier">yield_handler</span><span class="special">&lt;</span><span class="identifier">T</span><span class="special">&gt;&gt;</span></code>:
</p>
<p>
</p>
<pre class="programlisting"><span class="comment">// asio constructs an async_result&lt;&gt; instance from the yield_handler specified</span>
<span class="comment">// by handler_type&lt;&gt;::type. A particular asio async method constructs the</span>
<span class="comment">// yield_handler, constructs this async_result specialization from it, then</span>
<span class="comment">// returns the result of calling its get() method.</span>
<span class="keyword">template</span><span class="special">&lt;</span> <span class="keyword">typename</span> <span class="identifier">T</span> <span class="special">&gt;</span>
<span class="keyword">class</span> <span class="identifier">async_result</span><span class="special">&lt;</span> <span class="identifier">boost</span><span class="special">::</span><span class="identifier">fibers</span><span class="special">::</span><span class="identifier">asio</span><span class="special">::</span><span class="identifier">detail</span><span class="special">::</span><span class="identifier">yield_handler</span><span class="special">&lt;</span> <span class="identifier">T</span> <span class="special">&gt;</span> <span class="special">&gt;</span> <span class="special">:</span>
<span class="keyword">public</span> <span class="identifier">boost</span><span class="special">::</span><span class="identifier">fibers</span><span class="special">::</span><span class="identifier">asio</span><span class="special">::</span><span class="identifier">detail</span><span class="special">::</span><span class="identifier">async_result_base</span> <span class="special">{</span>
<span class="keyword">public</span><span class="special">:</span>
<span class="comment">// type returned by get()</span>
<span class="keyword">typedef</span> <span class="identifier">T</span> <span class="identifier">type</span><span class="special">;</span>
<span class="keyword">explicit</span> <span class="identifier">async_result</span><span class="special">(</span> <span class="identifier">boost</span><span class="special">::</span><span class="identifier">fibers</span><span class="special">::</span><span class="identifier">asio</span><span class="special">::</span><span class="identifier">detail</span><span class="special">::</span><span class="identifier">yield_handler</span><span class="special">&lt;</span> <span class="identifier">T</span> <span class="special">&gt;</span> <span class="special">&amp;</span> <span class="identifier">h</span><span class="special">)</span> <span class="special">:</span>
<span class="identifier">boost</span><span class="special">::</span><span class="identifier">fibers</span><span class="special">::</span><span class="identifier">asio</span><span class="special">::</span><span class="identifier">detail</span><span class="special">::</span><span class="identifier">async_result_base</span><span class="special">{</span> <span class="identifier">h</span> <span class="special">}</span> <span class="special">{</span>
<span class="comment">// Inject ptr to our value_ member into yield_handler&lt;&gt;: result will</span>
<span class="comment">// be stored here.</span>
<span class="identifier">h</span><span class="special">.</span><span class="identifier">value_</span> <span class="special">=</span> <span class="special">&amp;</span> <span class="identifier">value_</span><span class="special">;</span>
<span class="special">}</span>
<span class="comment">// asio async method returns result of calling get()</span>
<span class="identifier">type</span> <span class="identifier">get</span><span class="special">()</span> <span class="special">{</span>
<span class="identifier">boost</span><span class="special">::</span><span class="identifier">fibers</span><span class="special">::</span><span class="identifier">asio</span><span class="special">::</span><span class="identifier">detail</span><span class="special">::</span><span class="identifier">async_result_base</span><span class="special">::</span><span class="identifier">get</span><span class="special">();</span>
<span class="keyword">return</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">move</span><span class="special">(</span> <span class="identifier">value_</span><span class="special">);</span>
<span class="special">}</span>
<span class="keyword">private</span><span class="special">:</span>
<span class="identifier">type</span> <span class="identifier">value_</span><span class="special">{};</span>
<span class="special">};</span>
</pre>
<p>
</p>
<p>
this <code class="computeroutput"><span class="identifier">async_result</span><span class="special">&lt;&gt;</span></code>
specialization reserves a member of type <code class="computeroutput"><span class="identifier">T</span></code>
to receive the passed data item, and sets <code class="computeroutput"><span class="identifier">yield_handler</span><span class="special">&lt;</span><span class="identifier">T</span><span class="special">&gt;::</span><span class="identifier">value_</span></code> to point to its own data member.
</p>
<p>
<code class="computeroutput"><span class="identifier">async_result</span><span class="special">&lt;</span><span class="identifier">yield_handler</span><span class="special">&lt;</span><span class="identifier">T</span><span class="special">&gt;&gt;</span></code>
overrides <code class="computeroutput"><span class="identifier">get</span><span class="special">()</span></code>.
The override calls <code class="computeroutput"><span class="identifier">async_result_base</span><span class="special">::</span><span class="identifier">get</span><span class="special">()</span></code>,
so the calling fiber suspends as described above.
</p>
<p>
<code class="computeroutput"><span class="identifier">yield_handler</span><span class="special">&lt;</span><span class="identifier">T</span><span class="special">&gt;::</span><span class="keyword">operator</span><span class="special">()(</span><span class="identifier">error_code</span><span class="special">,</span> <span class="identifier">T</span><span class="special">)</span></code>
stores its passed <code class="computeroutput"><span class="identifier">T</span></code> value into
<code class="computeroutput"><span class="identifier">async_result</span><span class="special">&lt;</span><span class="identifier">yield_handler</span><span class="special">&lt;</span><span class="identifier">T</span><span class="special">&gt;&gt;::</span><span class="identifier">value_</span></code>.
</p>
<p>
Then it passes control to <code class="computeroutput"><span class="identifier">yield_handler_base</span><span class="special">::</span><span class="keyword">operator</span><span class="special">()(</span><span class="identifier">error_code</span><span class="special">)</span></code>
to deal with waking (and possibly migrating) the original fiber as described
above.
</p>
<p>
When <code class="computeroutput"><span class="identifier">async_result</span><span class="special">&lt;</span><span class="identifier">yield_handler</span><span class="special">&lt;</span><span class="identifier">T</span><span class="special">&gt;&gt;::</span><span class="identifier">get</span><span class="special">()</span></code> resumes,
it returns the stored <code class="computeroutput"><span class="identifier">value_</span></code>
to <code class="computeroutput"><span class="identifier">async_something</span><span class="special">()</span></code>
and ultimately to <code class="computeroutput"><span class="identifier">async_something</span><span class="special">()</span></code>'s caller.
</p>
<p>
The case of a callback signature <code class="computeroutput"><span class="keyword">void</span><span class="special">(</span><span class="identifier">T</span><span class="special">)</span></code>
is handled by having <code class="computeroutput"><span class="identifier">yield_handler</span><span class="special">&lt;</span><span class="identifier">T</span><span class="special">&gt;::</span><span class="keyword">operator</span><span class="special">()(</span><span class="identifier">T</span><span class="special">)</span></code> engage
the <code class="computeroutput"><span class="keyword">void</span><span class="special">(</span><span class="identifier">error_code</span><span class="special">,</span> <span class="identifier">T</span><span class="special">)</span></code> machinery,
passing a <span class="quote">&#8220;<span class="quote">success</span>&#8221;</span> <code class="computeroutput"><span class="identifier">error_code</span></code>.
</p>
<p>
The source code above is found in <a href="../../../examples/asio/yield.hpp" target="_top">yield.hpp</a>
and <a href="../../../examples/asio/detail/yield.hpp" target="_top">detail/yield.hpp</a>.
</p>
<div class="footnotes">
<br><hr width="100" align="left">
<div class="footnote"><p><sup>[<a name="ftn.fiber.callbacks.f0" href="#fiber.callbacks.f0" class="para">5</a>] </sup>
This mechanism has been proposed as a conventional way to allow the caller
of an async function to specify completion handling: <a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2014/n4045.pdf" target="_top">N4045</a>.
</p></div>
<div class="footnote"><p><sup>[<a name="ftn.fiber.callbacks.f1" href="#fiber.callbacks.f1" class="para">6</a>] </sup>
per <a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2014/n4045.pdf" target="_top">N4045</a>
</p></div>
</div>
<div class="toc"><dl>
<dt><span class="section"><a href="callbacks/overview.html">Overview</a></span></dt>
<dt><span class="section"><a href="callbacks/return_errorcode.html">Return Errorcode</a></span></dt>
<dt><span class="section"><a href="callbacks/success_or_exception.html">Success or Exception</a></span></dt>
<dt><span class="section"><a href="callbacks/return_errorcode_or_data.html">Return Errorcode
or Data</a></span></dt>
<dt><span class="section"><a href="callbacks/data_or_exception.html">Data
or Exception</a></span></dt>
<dt><span class="section"><a href="callbacks/success_error_virtual_methods.html">Success/Error
Virtual Methods</a></span></dt>
<dt><span class="section"><a href="callbacks/then_there_s____boost_asio__.html">Then
There&#8217;s <a href="http://www.boost.org/doc/libs/release/libs/asio/index.html" target="_top">Boost.Asio</a></a></span></dt>
</dl></div>
</div>
<table xmlns:rev="http://www.cs.rpi.edu/~gregod/boost/tools/doc/revision" width="100%"><tr>
<td align="left"></td>
@@ -989,7 +51,7 @@
</tr></table>
<hr>
<div class="spirit-nav">
<a accesskey="p" href="migration.html"><img src="../../../../../doc/src/images/prev.png" alt="Prev"></a><a accesskey="u" href="../index.html"><img src="../../../../../doc/src/images/up.png" alt="Up"></a><a accesskey="h" href="../index.html"><img src="../../../../../doc/src/images/home.png" alt="Home"></a><a accesskey="n" href="nonblocking.html"><img src="../../../../../doc/src/images/next.png" alt="Next"></a>
<a accesskey="p" href="migration.html"><img src="../../../../../doc/src/images/prev.png" alt="Prev"></a><a accesskey="u" href="../index.html"><img src="../../../../../doc/src/images/up.png" alt="Up"></a><a accesskey="h" href="../index.html"><img src="../../../../../doc/src/images/home.png" alt="Home"></a><a accesskey="n" href="callbacks/overview.html"><img src="../../../../../doc/src/images/next.png" alt="Next"></a>
</div>
</body>
</html>

View File

@@ -0,0 +1,78 @@
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=US-ASCII">
<title>Data or Exception</title>
<link rel="stylesheet" href="../../../../../../doc/src/boostbook.css" type="text/css">
<meta name="generator" content="DocBook XSL Stylesheets V1.75.2">
<link rel="home" href="../../index.html" title="Chapter&#160;1.&#160;Fiber">
<link rel="up" href="../callbacks.html" title="Integrating Fibers with Asynchronous Callbacks">
<link rel="prev" href="return_errorcode_or_data.html" title="Return Errorcode or Data">
<link rel="next" href="success_error_virtual_methods.html" title="Success/Error Virtual Methods">
</head>
<body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF">
<table cellpadding="2" width="100%"><tr>
<td valign="top"><img alt="Boost C++ Libraries" width="277" height="86" src="../../../../../../boost.png"></td>
<td align="center"><a href="../../../../../../index.html">Home</a></td>
<td align="center"><a href="../../../../../../libs/libraries.htm">Libraries</a></td>
<td align="center"><a href="http://www.boost.org/users/people.html">People</a></td>
<td align="center"><a href="http://www.boost.org/users/faq.html">FAQ</a></td>
<td align="center"><a href="../../../../../../more/index.htm">More</a></td>
</tr></table>
<hr>
<div class="spirit-nav">
<a accesskey="p" href="return_errorcode_or_data.html"><img src="../../../../../../doc/src/images/prev.png" alt="Prev"></a><a accesskey="u" href="../callbacks.html"><img src="../../../../../../doc/src/images/up.png" alt="Up"></a><a accesskey="h" href="../../index.html"><img src="../../../../../../doc/src/images/home.png" alt="Home"></a><a accesskey="n" href="success_error_virtual_methods.html"><img src="../../../../../../doc/src/images/next.png" alt="Next"></a>
</div>
<div class="section">
<div class="titlepage"><div><div><h3 class="title">
<a name="fiber.callbacks.data_or_exception"></a><a name="Data_or_Exception"></a><a class="link" href="data_or_exception.html" title="Data or Exception">Data
or Exception</a>
</h3></div></div></div>
<p>
But a more natural API for a function that obtains data is to return only
the data on success, throwing an exception on error.
</p>
<p>
As with <code class="computeroutput"><span class="identifier">write</span><span class="special">()</span></code>
above, it&#8217;s certainly possible to code a <code class="computeroutput"><span class="identifier">read</span><span class="special">()</span></code> wrapper in terms of <code class="computeroutput"><span class="identifier">read_ec</span><span class="special">()</span></code>. But since a given application is unlikely
to need both, let&#8217;s code <code class="computeroutput"><span class="identifier">read</span><span class="special">()</span></code> from scratch, leveraging <a class="link" href="../synchronization/futures/promise.html#promise_set_exception"><code class="computeroutput">promise::set_exception()</code></a>:
</p>
<p>
</p>
<pre class="programlisting"><span class="identifier">std</span><span class="special">::</span><span class="identifier">string</span> <span class="identifier">read</span><span class="special">(</span> <span class="identifier">AsyncAPI</span> <span class="special">&amp;</span> <span class="identifier">api</span><span class="special">)</span> <span class="special">{</span>
<span class="identifier">boost</span><span class="special">::</span><span class="identifier">fibers</span><span class="special">::</span><span class="identifier">promise</span><span class="special">&lt;</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">string</span> <span class="special">&gt;</span> <span class="identifier">promise</span><span class="special">;</span>
<span class="identifier">boost</span><span class="special">::</span><span class="identifier">fibers</span><span class="special">::</span><span class="identifier">future</span><span class="special">&lt;</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">string</span> <span class="special">&gt;</span> <span class="identifier">future</span><span class="special">(</span> <span class="identifier">promise</span><span class="special">.</span><span class="identifier">get_future</span><span class="special">()</span> <span class="special">);</span>
<span class="comment">// Both 'promise' and 'future' will survive until our lambda has been</span>
<span class="comment">// called.</span>
<span class="identifier">api</span><span class="special">.</span><span class="identifier">init_read</span><span class="special">([&amp;</span><span class="identifier">promise</span><span class="special">](</span> <span class="identifier">AsyncAPI</span><span class="special">::</span><span class="identifier">errorcode</span> <span class="identifier">ec</span><span class="special">,</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">string</span> <span class="keyword">const</span><span class="special">&amp;</span> <span class="identifier">data</span><span class="special">)</span> <span class="keyword">mutable</span> <span class="special">{</span>
<span class="keyword">if</span> <span class="special">(</span> <span class="special">!</span> <span class="identifier">ec</span><span class="special">)</span> <span class="special">{</span>
<span class="identifier">promise</span><span class="special">.</span><span class="identifier">set_value</span><span class="special">(</span> <span class="identifier">data</span><span class="special">);</span>
<span class="special">}</span> <span class="keyword">else</span> <span class="special">{</span>
<span class="identifier">promise</span><span class="special">.</span><span class="identifier">set_exception</span><span class="special">(</span>
<span class="identifier">std</span><span class="special">::</span><span class="identifier">make_exception_ptr</span><span class="special">(</span>
<span class="identifier">make_exception</span><span class="special">(</span><span class="string">"read"</span><span class="special">,</span> <span class="identifier">ec</span><span class="special">)</span> <span class="special">)</span> <span class="special">);</span>
<span class="special">}</span>
<span class="special">});</span>
<span class="keyword">return</span> <span class="identifier">future</span><span class="special">.</span><span class="identifier">get</span><span class="special">();</span>
<span class="special">}</span>
</pre>
<p>
</p>
<p>
<a class="link" href="../synchronization/futures/future.html#future_get"><code class="computeroutput">future::get()</code></a> will do the right thing, either returning <code class="computeroutput"><span class="identifier">std</span><span class="special">::</span><span class="identifier">string</span></code>
or throwing an exception.
</p>
</div>
<table xmlns:rev="http://www.cs.rpi.edu/~gregod/boost/tools/doc/revision" width="100%"><tr>
<td align="left"></td>
<td align="right"><div class="copyright-footer">Copyright &#169; 2013 Oliver Kowalke<p>
Distributed under the Boost Software License, Version 1.0. (See accompanying
file LICENSE_1_0.txt or copy at <a href="http://www.boost.org/LICENSE_1_0.txt" target="_top">http://www.boost.org/LICENSE_1_0.txt</a>)
</p>
</div></td>
</tr></table>
<hr>
<div class="spirit-nav">
<a accesskey="p" href="return_errorcode_or_data.html"><img src="../../../../../../doc/src/images/prev.png" alt="Prev"></a><a accesskey="u" href="../callbacks.html"><img src="../../../../../../doc/src/images/up.png" alt="Up"></a><a accesskey="h" href="../../index.html"><img src="../../../../../../doc/src/images/home.png" alt="Home"></a><a accesskey="n" href="success_error_virtual_methods.html"><img src="../../../../../../doc/src/images/next.png" alt="Next"></a>
</div>
</body>
</html>

View File

@@ -0,0 +1,106 @@
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=US-ASCII">
<title>Overview</title>
<link rel="stylesheet" href="../../../../../../doc/src/boostbook.css" type="text/css">
<meta name="generator" content="DocBook XSL Stylesheets V1.75.2">
<link rel="home" href="../../index.html" title="Chapter&#160;1.&#160;Fiber">
<link rel="up" href="../callbacks.html" title="Integrating Fibers with Asynchronous Callbacks">
<link rel="prev" href="../callbacks.html" title="Integrating Fibers with Asynchronous Callbacks">
<link rel="next" href="return_errorcode.html" title="Return Errorcode">
</head>
<body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF">
<table cellpadding="2" width="100%"><tr>
<td valign="top"><img alt="Boost C++ Libraries" width="277" height="86" src="../../../../../../boost.png"></td>
<td align="center"><a href="../../../../../../index.html">Home</a></td>
<td align="center"><a href="../../../../../../libs/libraries.htm">Libraries</a></td>
<td align="center"><a href="http://www.boost.org/users/people.html">People</a></td>
<td align="center"><a href="http://www.boost.org/users/faq.html">FAQ</a></td>
<td align="center"><a href="../../../../../../more/index.htm">More</a></td>
</tr></table>
<hr>
<div class="spirit-nav">
<a accesskey="p" href="../callbacks.html"><img src="../../../../../../doc/src/images/prev.png" alt="Prev"></a><a accesskey="u" href="../callbacks.html"><img src="../../../../../../doc/src/images/up.png" alt="Up"></a><a accesskey="h" href="../../index.html"><img src="../../../../../../doc/src/images/home.png" alt="Home"></a><a accesskey="n" href="return_errorcode.html"><img src="../../../../../../doc/src/images/next.png" alt="Next"></a>
</div>
<div class="section">
<div class="titlepage"><div><div><h3 class="title">
<a name="fiber.callbacks.overview"></a><a class="link" href="overview.html" title="Overview">Overview</a>
</h3></div></div></div>
<p>
One of the primary benefits of <span class="bold"><strong>Boost.Fiber</strong></span>
is the ability to use asynchronous operations for efficiency, while at the
same time structuring the calling code <span class="emphasis"><em>as if</em></span> 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 <span class="bold"><strong>Boost.Fiber</strong></span>
with an arbitrary async operation.
</p>
<p>
For purposes of illustration, consider the following hypothetical API:
</p>
<p>
</p>
<pre class="programlisting"><span class="keyword">class</span> <span class="identifier">AsyncAPI</span> <span class="special">{</span>
<span class="keyword">public</span><span class="special">:</span>
<span class="comment">// constructor acquires some resource that can be read and written</span>
<span class="identifier">AsyncAPI</span><span class="special">();</span>
<span class="comment">// callbacks accept an int error code; 0 == success</span>
<span class="keyword">typedef</span> <span class="keyword">int</span> <span class="identifier">errorcode</span><span class="special">;</span>
<span class="comment">// write callback only needs to indicate success or failure</span>
<span class="keyword">void</span> <span class="identifier">init_write</span><span class="special">(</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">string</span> <span class="keyword">const</span><span class="special">&amp;</span> <span class="identifier">data</span><span class="special">,</span>
<span class="identifier">std</span><span class="special">::</span><span class="identifier">function</span><span class="special">&lt;</span> <span class="keyword">void</span><span class="special">(</span> <span class="identifier">errorcode</span><span class="special">)</span> <span class="special">&gt;</span> <span class="keyword">const</span><span class="special">&amp;</span> <span class="identifier">callback</span><span class="special">);</span>
<span class="comment">// read callback needs to accept both errorcode and data</span>
<span class="keyword">void</span> <span class="identifier">init_read</span><span class="special">(</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">function</span><span class="special">&lt;</span> <span class="keyword">void</span><span class="special">(</span> <span class="identifier">errorcode</span><span class="special">,</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">string</span> <span class="keyword">const</span><span class="special">&amp;)</span> <span class="special">&gt;</span> <span class="keyword">const</span><span class="special">&amp;);</span>
<span class="comment">// ... other operations ...</span>
<span class="special">};</span>
</pre>
<p>
</p>
<p>
The significant points about each of <code class="computeroutput"><span class="identifier">init_write</span><span class="special">()</span></code> and <code class="computeroutput"><span class="identifier">init_read</span><span class="special">()</span></code> are:
</p>
<div class="itemizedlist"><ul class="itemizedlist" type="disc">
<li class="listitem">
The <code class="computeroutput"><span class="identifier">AsyncAPI</span></code> method only
initiates the operation. It returns immediately, while the requested
operation is still pending.
</li>
<li class="listitem">
The method accepts a callback. When the operation completes, the callback
is called with relevant parameters (error code, data if applicable).
</li>
</ul></div>
<p>
We would like to wrap these asynchronous methods in functions that appear
synchronous by blocking the calling fiber until the operation completes.
This lets us use the wrapper function&#8217;s return value to deliver relevant data.
</p>
<div class="tip"><table border="0" summary="Tip">
<tr>
<td rowspan="2" align="center" valign="top" width="25"><img alt="[Tip]" src="../../../../../../doc/src/images/tip.png"></td>
<th align="left">Tip</th>
</tr>
<tr><td align="left" valign="top"><p>
<a class="link" href="../synchronization/futures/promise.html#class_promise"><code class="computeroutput">promise&lt;&gt;</code></a> and <a class="link" href="../synchronization/futures/future.html#class_future"><code class="computeroutput">future&lt;&gt;</code></a> are your friends
here.
</p></td></tr>
</table></div>
</div>
<table xmlns:rev="http://www.cs.rpi.edu/~gregod/boost/tools/doc/revision" width="100%"><tr>
<td align="left"></td>
<td align="right"><div class="copyright-footer">Copyright &#169; 2013 Oliver Kowalke<p>
Distributed under the Boost Software License, Version 1.0. (See accompanying
file LICENSE_1_0.txt or copy at <a href="http://www.boost.org/LICENSE_1_0.txt" target="_top">http://www.boost.org/LICENSE_1_0.txt</a>)
</p>
</div></td>
</tr></table>
<hr>
<div class="spirit-nav">
<a accesskey="p" href="../callbacks.html"><img src="../../../../../../doc/src/images/prev.png" alt="Prev"></a><a accesskey="u" href="../callbacks.html"><img src="../../../../../../doc/src/images/up.png" alt="Up"></a><a accesskey="h" href="../../index.html"><img src="../../../../../../doc/src/images/home.png" alt="Home"></a><a accesskey="n" href="return_errorcode.html"><img src="../../../../../../doc/src/images/next.png" alt="Next"></a>
</div>
</body>
</html>

View File

@@ -0,0 +1,103 @@
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=US-ASCII">
<title>Return Errorcode</title>
<link rel="stylesheet" href="../../../../../../doc/src/boostbook.css" type="text/css">
<meta name="generator" content="DocBook XSL Stylesheets V1.75.2">
<link rel="home" href="../../index.html" title="Chapter&#160;1.&#160;Fiber">
<link rel="up" href="../callbacks.html" title="Integrating Fibers with Asynchronous Callbacks">
<link rel="prev" href="overview.html" title="Overview">
<link rel="next" href="success_or_exception.html" title="Success or Exception">
</head>
<body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF">
<table cellpadding="2" width="100%"><tr>
<td valign="top"><img alt="Boost C++ Libraries" width="277" height="86" src="../../../../../../boost.png"></td>
<td align="center"><a href="../../../../../../index.html">Home</a></td>
<td align="center"><a href="../../../../../../libs/libraries.htm">Libraries</a></td>
<td align="center"><a href="http://www.boost.org/users/people.html">People</a></td>
<td align="center"><a href="http://www.boost.org/users/faq.html">FAQ</a></td>
<td align="center"><a href="../../../../../../more/index.htm">More</a></td>
</tr></table>
<hr>
<div class="spirit-nav">
<a accesskey="p" href="overview.html"><img src="../../../../../../doc/src/images/prev.png" alt="Prev"></a><a accesskey="u" href="../callbacks.html"><img src="../../../../../../doc/src/images/up.png" alt="Up"></a><a accesskey="h" href="../../index.html"><img src="../../../../../../doc/src/images/home.png" alt="Home"></a><a accesskey="n" href="success_or_exception.html"><img src="../../../../../../doc/src/images/next.png" alt="Next"></a>
</div>
<div class="section">
<div class="titlepage"><div><div><h3 class="title">
<a name="fiber.callbacks.return_errorcode"></a><a class="link" href="return_errorcode.html" title="Return Errorcode">Return Errorcode</a>
</h3></div></div></div>
<p>
The <code class="computeroutput"><span class="identifier">AsyncAPI</span><span class="special">::</span><span class="identifier">init_write</span><span class="special">()</span></code>
callback passes only an <code class="computeroutput"><span class="identifier">errorcode</span></code>.
If we simply want the blocking wrapper to return that <code class="computeroutput"><span class="identifier">errorcode</span></code>,
this is an extremely straightforward use of <a class="link" href="../synchronization/futures/promise.html#class_promise"><code class="computeroutput">promise&lt;&gt;</code></a> and
<a class="link" href="../synchronization/futures/future.html#class_future"><code class="computeroutput">future&lt;&gt;</code></a>:
</p>
<p>
</p>
<pre class="programlisting"><span class="identifier">AsyncAPI</span><span class="special">::</span><span class="identifier">errorcode</span> <span class="identifier">write_ec</span><span class="special">(</span> <span class="identifier">AsyncAPI</span> <span class="special">&amp;</span> <span class="identifier">api</span><span class="special">,</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">string</span> <span class="keyword">const</span><span class="special">&amp;</span> <span class="identifier">data</span><span class="special">)</span> <span class="special">{</span>
<span class="identifier">boost</span><span class="special">::</span><span class="identifier">fibers</span><span class="special">::</span><span class="identifier">promise</span><span class="special">&lt;</span> <span class="identifier">AsyncAPI</span><span class="special">::</span><span class="identifier">errorcode</span> <span class="special">&gt;</span> <span class="identifier">promise</span><span class="special">;</span>
<span class="identifier">boost</span><span class="special">::</span><span class="identifier">fibers</span><span class="special">::</span><span class="identifier">future</span><span class="special">&lt;</span> <span class="identifier">AsyncAPI</span><span class="special">::</span><span class="identifier">errorcode</span> <span class="special">&gt;</span> <span class="identifier">future</span><span class="special">(</span> <span class="identifier">promise</span><span class="special">.</span><span class="identifier">get_future</span><span class="special">()</span> <span class="special">);</span>
<span class="comment">// In general, even though we block waiting for future::get() and therefore</span>
<span class="comment">// won't destroy 'promise' until promise::set_value() has been called, we</span>
<span class="comment">// are advised that with threads it's possible for ~promise() to be</span>
<span class="comment">// entered before promise::set_value() has returned. While that shouldn't</span>
<span class="comment">// happen with fibers::promise, a robust way to deal with the lifespan</span>
<span class="comment">// issue is to bind 'promise' into our lambda. Since promise is move-only,</span>
<span class="comment">// use initialization capture.</span>
<span class="identifier">api</span><span class="special">.</span><span class="identifier">init_write</span><span class="special">(</span>
<span class="identifier">data</span><span class="special">,</span>
<span class="special">[&amp;</span><span class="identifier">promise</span><span class="special">](</span> <span class="identifier">AsyncAPI</span><span class="special">::</span><span class="identifier">errorcode</span> <span class="identifier">ec</span><span class="special">)</span> <span class="keyword">mutable</span> <span class="special">{</span>
<span class="identifier">promise</span><span class="special">.</span><span class="identifier">set_value</span><span class="special">(</span> <span class="identifier">ec</span><span class="special">);</span>
<span class="special">});</span>
<span class="keyword">return</span> <span class="identifier">future</span><span class="special">.</span><span class="identifier">get</span><span class="special">();</span>
<span class="special">}</span>
</pre>
<p>
</p>
<p>
All we have to do is:
</p>
<div class="orderedlist"><ol class="orderedlist" type="1">
<li class="listitem">
Instantiate a <code class="computeroutput"><span class="identifier">promise</span><span class="special">&lt;&gt;</span></code> of correct type.
</li>
<li class="listitem">
Obtain its <code class="computeroutput"><span class="identifier">future</span><span class="special">&lt;&gt;</span></code>.
</li>
<li class="listitem">
Arrange for the callback to call <a class="link" href="../synchronization/futures/promise.html#promise_set_value"><code class="computeroutput">promise::set_value()</code></a>.
</li>
<li class="listitem">
Block on <a class="link" href="../synchronization/futures/future.html#future_get"><code class="computeroutput">future::get()</code></a>.
</li>
</ol></div>
<div class="note"><table border="0" summary="Note">
<tr>
<td rowspan="2" align="center" valign="top" width="25"><img alt="[Note]" src="../../../../../../doc/src/images/note.png"></td>
<th align="left">Note</th>
</tr>
<tr><td align="left" valign="top"><p>
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, <a href="../../../../examples/adapt_callbacks.cpp" target="_top">the
example program&#8217;s</a> dummy <code class="computeroutput"><span class="identifier">AsyncAPI</span></code>
implementation illustrates that: it simulates async I/O by launching a
new thread that sleeps briefly and then calls the relevant callback.
</p></td></tr>
</table></div>
</div>
<table xmlns:rev="http://www.cs.rpi.edu/~gregod/boost/tools/doc/revision" width="100%"><tr>
<td align="left"></td>
<td align="right"><div class="copyright-footer">Copyright &#169; 2013 Oliver Kowalke<p>
Distributed under the Boost Software License, Version 1.0. (See accompanying
file LICENSE_1_0.txt or copy at <a href="http://www.boost.org/LICENSE_1_0.txt" target="_top">http://www.boost.org/LICENSE_1_0.txt</a>)
</p>
</div></td>
</tr></table>
<hr>
<div class="spirit-nav">
<a accesskey="p" href="overview.html"><img src="../../../../../../doc/src/images/prev.png" alt="Prev"></a><a accesskey="u" href="../callbacks.html"><img src="../../../../../../doc/src/images/up.png" alt="Up"></a><a accesskey="h" href="../../index.html"><img src="../../../../../../doc/src/images/home.png" alt="Home"></a><a accesskey="n" href="success_or_exception.html"><img src="../../../../../../doc/src/images/next.png" alt="Next"></a>
</div>
</body>
</html>

View File

@@ -0,0 +1,75 @@
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=US-ASCII">
<title>Return Errorcode or Data</title>
<link rel="stylesheet" href="../../../../../../doc/src/boostbook.css" type="text/css">
<meta name="generator" content="DocBook XSL Stylesheets V1.75.2">
<link rel="home" href="../../index.html" title="Chapter&#160;1.&#160;Fiber">
<link rel="up" href="../callbacks.html" title="Integrating Fibers with Asynchronous Callbacks">
<link rel="prev" href="success_or_exception.html" title="Success or Exception">
<link rel="next" href="data_or_exception.html" title="Data or Exception">
</head>
<body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF">
<table cellpadding="2" width="100%"><tr>
<td valign="top"><img alt="Boost C++ Libraries" width="277" height="86" src="../../../../../../boost.png"></td>
<td align="center"><a href="../../../../../../index.html">Home</a></td>
<td align="center"><a href="../../../../../../libs/libraries.htm">Libraries</a></td>
<td align="center"><a href="http://www.boost.org/users/people.html">People</a></td>
<td align="center"><a href="http://www.boost.org/users/faq.html">FAQ</a></td>
<td align="center"><a href="../../../../../../more/index.htm">More</a></td>
</tr></table>
<hr>
<div class="spirit-nav">
<a accesskey="p" href="success_or_exception.html"><img src="../../../../../../doc/src/images/prev.png" alt="Prev"></a><a accesskey="u" href="../callbacks.html"><img src="../../../../../../doc/src/images/up.png" alt="Up"></a><a accesskey="h" href="../../index.html"><img src="../../../../../../doc/src/images/home.png" alt="Home"></a><a accesskey="n" href="data_or_exception.html"><img src="../../../../../../doc/src/images/next.png" alt="Next"></a>
</div>
<div class="section">
<div class="titlepage"><div><div><h3 class="title">
<a name="fiber.callbacks.return_errorcode_or_data"></a><a class="link" href="return_errorcode_or_data.html" title="Return Errorcode or Data">Return Errorcode
or Data</a>
</h3></div></div></div>
<p>
Things get a bit more interesting when the async operation&#8217;s callback passes
multiple data items of interest. One approach would be to use <code class="computeroutput"><span class="identifier">std</span><span class="special">::</span><span class="identifier">pair</span><span class="special">&lt;&gt;</span></code> to capture both:
</p>
<p>
</p>
<pre class="programlisting"><span class="identifier">std</span><span class="special">::</span><span class="identifier">pair</span><span class="special">&lt;</span> <span class="identifier">AsyncAPI</span><span class="special">::</span><span class="identifier">errorcode</span><span class="special">,</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">string</span> <span class="special">&gt;</span> <span class="identifier">read_ec</span><span class="special">(</span> <span class="identifier">AsyncAPI</span> <span class="special">&amp;</span> <span class="identifier">api</span><span class="special">)</span> <span class="special">{</span>
<span class="keyword">typedef</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">pair</span><span class="special">&lt;</span> <span class="identifier">AsyncAPI</span><span class="special">::</span><span class="identifier">errorcode</span><span class="special">,</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">string</span> <span class="special">&gt;</span> <span class="identifier">result_pair</span><span class="special">;</span>
<span class="identifier">boost</span><span class="special">::</span><span class="identifier">fibers</span><span class="special">::</span><span class="identifier">promise</span><span class="special">&lt;</span> <span class="identifier">result_pair</span> <span class="special">&gt;</span> <span class="identifier">promise</span><span class="special">;</span>
<span class="identifier">boost</span><span class="special">::</span><span class="identifier">fibers</span><span class="special">::</span><span class="identifier">future</span><span class="special">&lt;</span> <span class="identifier">result_pair</span> <span class="special">&gt;</span> <span class="identifier">future</span><span class="special">(</span> <span class="identifier">promise</span><span class="special">.</span><span class="identifier">get_future</span><span class="special">()</span> <span class="special">);</span>
<span class="comment">// We promise that both 'promise' and 'future' will survive until our</span>
<span class="comment">// lambda has been called.</span>
<span class="identifier">api</span><span class="special">.</span><span class="identifier">init_read</span><span class="special">([&amp;</span><span class="identifier">promise</span><span class="special">](</span> <span class="identifier">AsyncAPI</span><span class="special">::</span><span class="identifier">errorcode</span> <span class="identifier">ec</span><span class="special">,</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">string</span> <span class="keyword">const</span><span class="special">&amp;</span> <span class="identifier">data</span><span class="special">)</span> <span class="keyword">mutable</span> <span class="special">{</span>
<span class="identifier">promise</span><span class="special">.</span><span class="identifier">set_value</span><span class="special">(</span> <span class="identifier">result_pair</span><span class="special">(</span> <span class="identifier">ec</span><span class="special">,</span> <span class="identifier">data</span><span class="special">)</span> <span class="special">);</span>
<span class="special">});</span>
<span class="keyword">return</span> <span class="identifier">future</span><span class="special">.</span><span class="identifier">get</span><span class="special">();</span>
<span class="special">}</span>
</pre>
<p>
</p>
<p>
Once you bundle the interesting data in <code class="computeroutput"><span class="identifier">std</span><span class="special">::</span><span class="identifier">pair</span><span class="special">&lt;&gt;</span></code>, the code is effectively identical
to <code class="computeroutput"><span class="identifier">write_ec</span><span class="special">()</span></code>.
You can call it like this:
</p>
<p>
</p>
<pre class="programlisting"><span class="identifier">std</span><span class="special">::</span><span class="identifier">tie</span><span class="special">(</span> <span class="identifier">ec</span><span class="special">,</span> <span class="identifier">data</span><span class="special">)</span> <span class="special">=</span> <span class="identifier">read_ec</span><span class="special">(</span> <span class="identifier">api</span><span class="special">);</span>
</pre>
<p>
</p>
</div>
<table xmlns:rev="http://www.cs.rpi.edu/~gregod/boost/tools/doc/revision" width="100%"><tr>
<td align="left"></td>
<td align="right"><div class="copyright-footer">Copyright &#169; 2013 Oliver Kowalke<p>
Distributed under the Boost Software License, Version 1.0. (See accompanying
file LICENSE_1_0.txt or copy at <a href="http://www.boost.org/LICENSE_1_0.txt" target="_top">http://www.boost.org/LICENSE_1_0.txt</a>)
</p>
</div></td>
</tr></table>
<hr>
<div class="spirit-nav">
<a accesskey="p" href="success_or_exception.html"><img src="../../../../../../doc/src/images/prev.png" alt="Prev"></a><a accesskey="u" href="../callbacks.html"><img src="../../../../../../doc/src/images/up.png" alt="Up"></a><a accesskey="h" href="../../index.html"><img src="../../../../../../doc/src/images/home.png" alt="Home"></a><a accesskey="n" href="data_or_exception.html"><img src="../../../../../../doc/src/images/next.png" alt="Next"></a>
</div>
</body>
</html>

View File

@@ -0,0 +1,131 @@
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=US-ASCII">
<title>Success/Error Virtual Methods</title>
<link rel="stylesheet" href="../../../../../../doc/src/boostbook.css" type="text/css">
<meta name="generator" content="DocBook XSL Stylesheets V1.75.2">
<link rel="home" href="../../index.html" title="Chapter&#160;1.&#160;Fiber">
<link rel="up" href="../callbacks.html" title="Integrating Fibers with Asynchronous Callbacks">
<link rel="prev" href="data_or_exception.html" title="Data or Exception">
<link rel="next" href="then_there_s____boost_asio__.html" title="Then There&#8217;s Boost.Asio">
</head>
<body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF">
<table cellpadding="2" width="100%"><tr>
<td valign="top"><img alt="Boost C++ Libraries" width="277" height="86" src="../../../../../../boost.png"></td>
<td align="center"><a href="../../../../../../index.html">Home</a></td>
<td align="center"><a href="../../../../../../libs/libraries.htm">Libraries</a></td>
<td align="center"><a href="http://www.boost.org/users/people.html">People</a></td>
<td align="center"><a href="http://www.boost.org/users/faq.html">FAQ</a></td>
<td align="center"><a href="../../../../../../more/index.htm">More</a></td>
</tr></table>
<hr>
<div class="spirit-nav">
<a accesskey="p" href="data_or_exception.html"><img src="../../../../../../doc/src/images/prev.png" alt="Prev"></a><a accesskey="u" href="../callbacks.html"><img src="../../../../../../doc/src/images/up.png" alt="Up"></a><a accesskey="h" href="../../index.html"><img src="../../../../../../doc/src/images/home.png" alt="Home"></a><a accesskey="n" href="then_there_s____boost_asio__.html"><img src="../../../../../../doc/src/images/next.png" alt="Next"></a>
</div>
<div class="section">
<div class="titlepage"><div><div><h3 class="title">
<a name="fiber.callbacks.success_error_virtual_methods"></a><a class="link" href="success_error_virtual_methods.html" title="Success/Error Virtual Methods">Success/Error
Virtual Methods</a>
</h3></div></div></div>
<p>
One classic approach to completion notification is to define an abstract
base class with <code class="computeroutput"><span class="identifier">success</span><span class="special">()</span></code>
and <code class="computeroutput"><span class="identifier">error</span><span class="special">()</span></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:
</p>
<p>
</p>
<pre class="programlisting"><span class="comment">// every async operation receives a subclass instance of this abstract base</span>
<span class="comment">// class through which to communicate its result</span>
<span class="keyword">struct</span> <span class="identifier">Response</span> <span class="special">{</span>
<span class="keyword">typedef</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">shared_ptr</span><span class="special">&lt;</span> <span class="identifier">Response</span> <span class="special">&gt;</span> <span class="identifier">ptr</span><span class="special">;</span>
<span class="comment">// called if the operation succeeds</span>
<span class="keyword">virtual</span> <span class="keyword">void</span> <span class="identifier">success</span><span class="special">(</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">string</span> <span class="keyword">const</span><span class="special">&amp;</span> <span class="identifier">data</span><span class="special">)</span> <span class="special">=</span> <span class="number">0</span><span class="special">;</span>
<span class="comment">// called if the operation fails</span>
<span class="keyword">virtual</span> <span class="keyword">void</span> <span class="identifier">error</span><span class="special">(</span> <span class="identifier">AsyncAPIBase</span><span class="special">::</span><span class="identifier">errorcode</span> <span class="identifier">ec</span><span class="special">)</span> <span class="special">=</span> <span class="number">0</span><span class="special">;</span>
<span class="special">};</span>
</pre>
<p>
</p>
<p>
Now the <code class="computeroutput"><span class="identifier">AsyncAPI</span></code> operation
might look more like this:
</p>
<p>
</p>
<pre class="programlisting"><span class="comment">// derive Response subclass, instantiate, pass Response::ptr</span>
<span class="keyword">void</span> <span class="identifier">init_read</span><span class="special">(</span> <span class="identifier">Response</span><span class="special">::</span><span class="identifier">ptr</span><span class="special">);</span>
</pre>
<p>
</p>
<p>
We can address this by writing a one-size-fits-all <code class="computeroutput"><span class="identifier">PromiseResponse</span></code>:
</p>
<p>
</p>
<pre class="programlisting"><span class="keyword">class</span> <span class="identifier">PromiseResponse</span><span class="special">:</span> <span class="keyword">public</span> <span class="identifier">Response</span> <span class="special">{</span>
<span class="keyword">public</span><span class="special">:</span>
<span class="comment">// called if the operation succeeds</span>
<span class="keyword">virtual</span> <span class="keyword">void</span> <span class="identifier">success</span><span class="special">(</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">string</span> <span class="keyword">const</span><span class="special">&amp;</span> <span class="identifier">data</span><span class="special">)</span> <span class="special">{</span>
<span class="identifier">promise_</span><span class="special">.</span><span class="identifier">set_value</span><span class="special">(</span> <span class="identifier">data</span><span class="special">);</span>
<span class="special">}</span>
<span class="comment">// called if the operation fails</span>
<span class="keyword">virtual</span> <span class="keyword">void</span> <span class="identifier">error</span><span class="special">(</span> <span class="identifier">AsyncAPIBase</span><span class="special">::</span><span class="identifier">errorcode</span> <span class="identifier">ec</span><span class="special">)</span> <span class="special">{</span>
<span class="identifier">promise_</span><span class="special">.</span><span class="identifier">set_exception</span><span class="special">(</span>
<span class="identifier">std</span><span class="special">::</span><span class="identifier">make_exception_ptr</span><span class="special">(</span>
<span class="identifier">make_exception</span><span class="special">(</span><span class="string">"read"</span><span class="special">,</span> <span class="identifier">ec</span><span class="special">)</span> <span class="special">)</span> <span class="special">);</span>
<span class="special">}</span>
<span class="identifier">boost</span><span class="special">::</span><span class="identifier">fibers</span><span class="special">::</span><span class="identifier">future</span><span class="special">&lt;</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">string</span> <span class="special">&gt;</span> <span class="identifier">get_future</span><span class="special">()</span> <span class="special">{</span>
<span class="keyword">return</span> <span class="identifier">promise_</span><span class="special">.</span><span class="identifier">get_future</span><span class="special">();</span>
<span class="special">}</span>
<span class="keyword">private</span><span class="special">:</span>
<span class="identifier">boost</span><span class="special">::</span><span class="identifier">fibers</span><span class="special">::</span><span class="identifier">promise</span><span class="special">&lt;</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">string</span> <span class="special">&gt;</span> <span class="identifier">promise_</span><span class="special">;</span>
<span class="special">};</span>
</pre>
<p>
</p>
<p>
Now we can simply obtain the <code class="computeroutput"><span class="identifier">future</span><span class="special">&lt;&gt;</span></code> from that <code class="computeroutput"><span class="identifier">PromiseResponse</span></code>
and wait on its <code class="computeroutput"><span class="identifier">get</span><span class="special">()</span></code>:
</p>
<p>
</p>
<pre class="programlisting"><span class="identifier">std</span><span class="special">::</span><span class="identifier">string</span> <span class="identifier">read</span><span class="special">(</span> <span class="identifier">AsyncAPI</span> <span class="special">&amp;</span> <span class="identifier">api</span><span class="special">)</span> <span class="special">{</span>
<span class="comment">// Because init_read() requires a shared_ptr, we must allocate our</span>
<span class="comment">// ResponsePromise on the heap, even though we know its lifespan.</span>
<span class="keyword">auto</span> <span class="identifier">promisep</span><span class="special">(</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">make_shared</span><span class="special">&lt;</span> <span class="identifier">PromiseResponse</span> <span class="special">&gt;()</span> <span class="special">);</span>
<span class="identifier">boost</span><span class="special">::</span><span class="identifier">fibers</span><span class="special">::</span><span class="identifier">future</span><span class="special">&lt;</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">string</span> <span class="special">&gt;</span> <span class="identifier">future</span><span class="special">(</span> <span class="identifier">promisep</span><span class="special">-&gt;</span><span class="identifier">get_future</span><span class="special">()</span> <span class="special">);</span>
<span class="comment">// Both 'promisep' and 'future' will survive until our lambda has been</span>
<span class="comment">// called.</span>
<span class="identifier">api</span><span class="special">.</span><span class="identifier">init_read</span><span class="special">(</span> <span class="identifier">promisep</span><span class="special">);</span>
<span class="keyword">return</span> <span class="identifier">future</span><span class="special">.</span><span class="identifier">get</span><span class="special">();</span>
<span class="special">}</span>
</pre>
<p>
</p>
<p>
The source code above is found in <a href="../../../../examples/adapt_callbacks.cpp" target="_top">adapt_callbacks.cpp</a>
and <a href="../../../../examples/adapt_method_calls.cpp" target="_top">adapt_method_calls.cpp</a>.
</p>
</div>
<table xmlns:rev="http://www.cs.rpi.edu/~gregod/boost/tools/doc/revision" width="100%"><tr>
<td align="left"></td>
<td align="right"><div class="copyright-footer">Copyright &#169; 2013 Oliver Kowalke<p>
Distributed under the Boost Software License, Version 1.0. (See accompanying
file LICENSE_1_0.txt or copy at <a href="http://www.boost.org/LICENSE_1_0.txt" target="_top">http://www.boost.org/LICENSE_1_0.txt</a>)
</p>
</div></td>
</tr></table>
<hr>
<div class="spirit-nav">
<a accesskey="p" href="data_or_exception.html"><img src="../../../../../../doc/src/images/prev.png" alt="Prev"></a><a accesskey="u" href="../callbacks.html"><img src="../../../../../../doc/src/images/up.png" alt="Up"></a><a accesskey="h" href="../../index.html"><img src="../../../../../../doc/src/images/home.png" alt="Home"></a><a accesskey="n" href="then_there_s____boost_asio__.html"><img src="../../../../../../doc/src/images/next.png" alt="Next"></a>
</div>
</body>
</html>

View File

@@ -0,0 +1,63 @@
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=US-ASCII">
<title>Success or Exception</title>
<link rel="stylesheet" href="../../../../../../doc/src/boostbook.css" type="text/css">
<meta name="generator" content="DocBook XSL Stylesheets V1.75.2">
<link rel="home" href="../../index.html" title="Chapter&#160;1.&#160;Fiber">
<link rel="up" href="../callbacks.html" title="Integrating Fibers with Asynchronous Callbacks">
<link rel="prev" href="return_errorcode.html" title="Return Errorcode">
<link rel="next" href="return_errorcode_or_data.html" title="Return Errorcode or Data">
</head>
<body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF">
<table cellpadding="2" width="100%"><tr>
<td valign="top"><img alt="Boost C++ Libraries" width="277" height="86" src="../../../../../../boost.png"></td>
<td align="center"><a href="../../../../../../index.html">Home</a></td>
<td align="center"><a href="../../../../../../libs/libraries.htm">Libraries</a></td>
<td align="center"><a href="http://www.boost.org/users/people.html">People</a></td>
<td align="center"><a href="http://www.boost.org/users/faq.html">FAQ</a></td>
<td align="center"><a href="../../../../../../more/index.htm">More</a></td>
</tr></table>
<hr>
<div class="spirit-nav">
<a accesskey="p" href="return_errorcode.html"><img src="../../../../../../doc/src/images/prev.png" alt="Prev"></a><a accesskey="u" href="../callbacks.html"><img src="../../../../../../doc/src/images/up.png" alt="Up"></a><a accesskey="h" href="../../index.html"><img src="../../../../../../doc/src/images/home.png" alt="Home"></a><a accesskey="n" href="return_errorcode_or_data.html"><img src="../../../../../../doc/src/images/next.png" alt="Next"></a>
</div>
<div class="section">
<div class="titlepage"><div><div><h3 class="title">
<a name="fiber.callbacks.success_or_exception"></a><a class="link" href="success_or_exception.html" title="Success or Exception">Success or Exception</a>
</h3></div></div></div>
<p>
A wrapper more aligned with modern C++ practice would use an exception, rather
than an <code class="computeroutput"><span class="identifier">errorcode</span></code>, to communicate
failure to its caller. This is straightforward to code in terms of <code class="computeroutput"><span class="identifier">write_ec</span><span class="special">()</span></code>:
</p>
<p>
</p>
<pre class="programlisting"><span class="keyword">void</span> <span class="identifier">write</span><span class="special">(</span> <span class="identifier">AsyncAPI</span> <span class="special">&amp;</span> <span class="identifier">api</span><span class="special">,</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">string</span> <span class="keyword">const</span><span class="special">&amp;</span> <span class="identifier">data</span><span class="special">)</span> <span class="special">{</span>
<span class="identifier">AsyncAPI</span><span class="special">::</span><span class="identifier">errorcode</span> <span class="identifier">ec</span> <span class="special">=</span> <span class="identifier">write_ec</span><span class="special">(</span> <span class="identifier">api</span><span class="special">,</span> <span class="identifier">data</span><span class="special">);</span>
<span class="keyword">if</span> <span class="special">(</span> <span class="identifier">ec</span><span class="special">)</span> <span class="special">{</span>
<span class="keyword">throw</span> <span class="identifier">make_exception</span><span class="special">(</span><span class="string">"write"</span><span class="special">,</span> <span class="identifier">ec</span><span class="special">);</span>
<span class="special">}</span>
<span class="special">}</span>
</pre>
<p>
</p>
<p>
The point is that since each fiber has its own stack, you need not repeat
messy boilerplate: normal encapsulation works.
</p>
</div>
<table xmlns:rev="http://www.cs.rpi.edu/~gregod/boost/tools/doc/revision" width="100%"><tr>
<td align="left"></td>
<td align="right"><div class="copyright-footer">Copyright &#169; 2013 Oliver Kowalke<p>
Distributed under the Boost Software License, Version 1.0. (See accompanying
file LICENSE_1_0.txt or copy at <a href="http://www.boost.org/LICENSE_1_0.txt" target="_top">http://www.boost.org/LICENSE_1_0.txt</a>)
</p>
</div></td>
</tr></table>
<hr>
<div class="spirit-nav">
<a accesskey="p" href="return_errorcode.html"><img src="../../../../../../doc/src/images/prev.png" alt="Prev"></a><a accesskey="u" href="../callbacks.html"><img src="../../../../../../doc/src/images/up.png" alt="Up"></a><a accesskey="h" href="../../index.html"><img src="../../../../../../doc/src/images/home.png" alt="Home"></a><a accesskey="n" href="return_errorcode_or_data.html"><img src="../../../../../../doc/src/images/next.png" alt="Next"></a>
</div>
</body>
</html>

View File

@@ -0,0 +1,606 @@
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=US-ASCII">
<title>Then There&#8217;s Boost.Asio</title>
<link rel="stylesheet" href="../../../../../../doc/src/boostbook.css" type="text/css">
<meta name="generator" content="DocBook XSL Stylesheets V1.75.2">
<link rel="home" href="../../index.html" title="Chapter&#160;1.&#160;Fiber">
<link rel="up" href="../callbacks.html" title="Integrating Fibers with Asynchronous Callbacks">
<link rel="prev" href="success_error_virtual_methods.html" title="Success/Error Virtual Methods">
<link rel="next" href="../nonblocking.html" title="Integrating Fibers with Nonblocking I/O">
</head>
<body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF">
<table cellpadding="2" width="100%"><tr>
<td valign="top"><img alt="Boost C++ Libraries" width="277" height="86" src="../../../../../../boost.png"></td>
<td align="center"><a href="../../../../../../index.html">Home</a></td>
<td align="center"><a href="../../../../../../libs/libraries.htm">Libraries</a></td>
<td align="center"><a href="http://www.boost.org/users/people.html">People</a></td>
<td align="center"><a href="http://www.boost.org/users/faq.html">FAQ</a></td>
<td align="center"><a href="../../../../../../more/index.htm">More</a></td>
</tr></table>
<hr>
<div class="spirit-nav">
<a accesskey="p" href="success_error_virtual_methods.html"><img src="../../../../../../doc/src/images/prev.png" alt="Prev"></a><a accesskey="u" href="../callbacks.html"><img src="../../../../../../doc/src/images/up.png" alt="Up"></a><a accesskey="h" href="../../index.html"><img src="../../../../../../doc/src/images/home.png" alt="Home"></a><a accesskey="n" href="../nonblocking.html"><img src="../../../../../../doc/src/images/next.png" alt="Next"></a>
</div>
<div class="section">
<div class="titlepage"><div><div><h3 class="title">
<a name="fiber.callbacks.then_there_s____boost_asio__"></a><a name="callbacks_asio"></a><a class="link" href="then_there_s____boost_asio__.html" title="Then There&#8217;s Boost.Asio">Then
There&#8217;s <a href="http://www.boost.org/doc/libs/release/libs/asio/index.html" target="_top">Boost.Asio</a></a>
</h3></div></div></div>
<p>
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 class="computeroutput"><span class="identifier">AsyncAPI</span></code> asynchronous
operations.
</p>
<p>
Fortunately we need not. Boost.Asio incorporates a mechanism<sup>[<a name="fiber.callbacks.then_there_s____boost_asio__.f0" href="#ftn.fiber.callbacks.then_there_s____boost_asio__.f0" class="footnote">4</a>]</sup> by which the caller can customize the notification behavior of
any async operation. Therefore we can construct a <span class="emphasis"><em>completion token</em></span>
which, when passed to a <a href="http://www.boost.org/doc/libs/release/libs/asio/index.html" target="_top">Boost.Asio</a>
async operation, requests blocking for the calling fiber.
</p>
<p>
A typical Asio async function might look something like this:<sup>[<a name="fiber.callbacks.then_there_s____boost_asio__.f1" href="#ftn.fiber.callbacks.then_there_s____boost_asio__.f1" class="footnote">5</a>]</sup>
</p>
<pre class="programlisting"><span class="keyword">template</span> <span class="special">&lt;</span> <span class="special">...,</span> <span class="keyword">class</span> <span class="identifier">CompletionToken</span> <span class="special">&gt;</span>
<span class="emphasis"><em>deduced_return_type</em></span>
<span class="identifier">async_something</span><span class="special">(</span> <span class="special">...</span> <span class="special">,</span> <span class="identifier">CompletionToken</span><span class="special">&amp;&amp;</span> <span class="identifier">token</span><span class="special">)</span>
<span class="special">{</span>
<span class="comment">// construct handler_type instance from CompletionToken</span>
<span class="identifier">handler_type</span><span class="special">&lt;</span><span class="identifier">CompletionToken</span><span class="special">,</span> <span class="special">...&gt;::</span><span class="identifier">type</span> <span class="bold"><strong><code class="computeroutput">handler(token)</code></strong></span><span class="special">;</span>
<span class="comment">// construct async_result instance from handler_type</span>
<span class="identifier">async_result</span><span class="special">&lt;</span><span class="keyword">decltype</span><span class="special">(</span><span class="identifier">handler</span><span class="special">)&gt;</span> <span class="bold"><strong><code class="computeroutput">result(handler)</code></strong></span><span class="special">;</span>
<span class="comment">// ... arrange to call handler on completion ...</span>
<span class="comment">// ... initiate actual I/O operation ...</span>
<span class="keyword">return</span> <span class="bold"><strong><code class="computeroutput">result.get()</code></strong></span><span class="special">;</span>
<span class="special">}</span>
</pre>
<p>
We will engage that mechanism, which is based on specializing Asio&#8217;s <code class="computeroutput"><span class="identifier">handler_type</span><span class="special">&lt;&gt;</span></code>
template for the <code class="computeroutput"><span class="identifier">CompletionToken</span></code>
type and the signature of the specific callback. The remainder of this discussion
will refer back to <code class="computeroutput"><span class="identifier">async_something</span><span class="special">()</span></code> as the Asio async function under consideration.
</p>
<p>
The implementation described below uses lower-level facilities than <code class="computeroutput"><span class="identifier">promise</span></code> and <code class="computeroutput"><span class="identifier">future</span></code>
because the <code class="computeroutput"><span class="identifier">promise</span></code> mechanism
interacts badly with <a href="http://www.boost.org/doc/libs/release/doc/html/boost_asio/reference/io_service/stop.html" target="_top"><code class="computeroutput"><span class="identifier">io_service</span><span class="special">::</span><span class="identifier">stop</span><span class="special">()</span></code></a>.
It produces <code class="computeroutput"><span class="identifier">broken_promise</span></code>
exceptions.
</p>
<p>
<code class="computeroutput"><span class="identifier">boost</span><span class="special">::</span><span class="identifier">fibers</span><span class="special">::</span><span class="identifier">asio</span><span class="special">::</span><span class="identifier">yield</span></code> is a completion token of this kind.
<code class="computeroutput"><span class="identifier">yield</span></code> is an instance of
<code class="computeroutput"><span class="identifier">yield_t</span></code>:
</p>
<p>
</p>
<pre class="programlisting"><span class="keyword">class</span> <span class="identifier">yield_t</span> <span class="special">{</span>
<span class="keyword">public</span><span class="special">:</span>
<span class="identifier">yield_t</span><span class="special">()</span> <span class="special">=</span> <span class="keyword">default</span><span class="special">;</span>
<span class="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.
*/</span>
<span class="identifier">yield_t</span> <span class="keyword">operator</span><span class="special">[](</span> <span class="identifier">boost</span><span class="special">::</span><span class="identifier">system</span><span class="special">::</span><span class="identifier">error_code</span> <span class="special">&amp;</span> <span class="identifier">ec</span><span class="special">)</span> <span class="keyword">const</span> <span class="special">{</span>
<span class="identifier">yield_t</span> <span class="identifier">tmp</span><span class="special">{</span> <span class="special">*</span> <span class="keyword">this</span> <span class="special">};</span>
<span class="identifier">tmp</span><span class="special">.</span><span class="identifier">ec_</span> <span class="special">=</span> <span class="special">&amp;</span> <span class="identifier">ec</span><span class="special">;</span>
<span class="keyword">return</span> <span class="identifier">tmp</span><span class="special">;</span>
<span class="special">}</span>
<span class="comment">//private:</span>
<span class="comment">// ptr to bound error_code instance if any</span>
<span class="identifier">boost</span><span class="special">::</span><span class="identifier">system</span><span class="special">::</span><span class="identifier">error_code</span> <span class="special">*</span> <span class="identifier">ec_</span><span class="special">{</span> <span class="keyword">nullptr</span> <span class="special">};</span>
<span class="special">};</span>
</pre>
<p>
</p>
<p>
<code class="computeroutput"><span class="identifier">yield_t</span></code> is in fact only a
placeholder, a way to trigger Boost.Asio customization. It can bind a <a href="http://www.boost.org/doc/libs/release/libs/system/doc/reference.html#Class-error_code" target="_top"><code class="computeroutput"><span class="identifier">boost</span><span class="special">::</span><span class="identifier">system</span><span class="special">::</span><span class="identifier">error_code</span></code></a> for use by the actual
handler.
</p>
<p>
<code class="computeroutput"><span class="identifier">yield</span></code> is declared as:
</p>
<p>
</p>
<pre class="programlisting"><span class="comment">// canonical instance</span>
<span class="keyword">thread_local</span> <span class="identifier">yield_t</span> <span class="identifier">yield</span><span class="special">{};</span>
</pre>
<p>
</p>
<p>
Asio customization is engaged by specializing <a href="http://www.boost.org/doc/libs/release/doc/html/boost_asio/reference/handler_type.html" target="_top"><code class="computeroutput"><span class="identifier">boost</span><span class="special">::</span><span class="identifier">asio</span><span class="special">::</span><span class="identifier">handler_type</span><span class="special">&lt;&gt;</span></code></a>
for <code class="computeroutput"><span class="identifier">yield_t</span></code>:
</p>
<p>
</p>
<pre class="programlisting"><span class="comment">// Handler type specialisation for fibers::asio::yield.</span>
<span class="comment">// When 'yield' is passed as a completion handler which accepts only</span>
<span class="comment">// error_code, use yield_handler&lt;void&gt;. yield_handler will take care of the</span>
<span class="comment">// error_code one way or another.</span>
<span class="keyword">template</span><span class="special">&lt;</span> <span class="keyword">typename</span> <span class="identifier">ReturnType</span> <span class="special">&gt;</span>
<span class="keyword">struct</span> <span class="identifier">handler_type</span><span class="special">&lt;</span> <span class="identifier">fibers</span><span class="special">::</span><span class="identifier">asio</span><span class="special">::</span><span class="identifier">yield_t</span><span class="special">,</span> <span class="identifier">ReturnType</span><span class="special">(</span> <span class="identifier">boost</span><span class="special">::</span><span class="identifier">system</span><span class="special">::</span><span class="identifier">error_code</span><span class="special">)</span> <span class="special">&gt;</span>
<span class="special">{</span> <span class="keyword">typedef</span> <span class="identifier">fibers</span><span class="special">::</span><span class="identifier">asio</span><span class="special">::</span><span class="identifier">detail</span><span class="special">::</span><span class="identifier">yield_handler</span><span class="special">&lt;</span> <span class="keyword">void</span> <span class="special">&gt;</span> <span class="identifier">type</span><span class="special">;</span> <span class="special">};</span>
</pre>
<p>
</p>
<p>
(There are actually four different specializations in <a href="../../../../examples/asio/detail/yield.hpp" target="_top">detail/yield.hpp</a>,
one for each of the four Asio async callback signatures we expect.)
</p>
<p>
The above directs Asio to use <code class="computeroutput"><span class="identifier">yield_handler</span></code>
as the actual handler for an async operation to which <code class="computeroutput"><span class="identifier">yield</span></code>
is passed. There&#8217;s a generic <code class="computeroutput"><span class="identifier">yield_handler</span><span class="special">&lt;</span><span class="identifier">T</span><span class="special">&gt;</span></code>
implementation and a <code class="computeroutput"><span class="identifier">yield_handler</span><span class="special">&lt;</span><span class="keyword">void</span><span class="special">&gt;</span></code>
specialization. Let&#8217;s start with the <code class="computeroutput"><span class="special">&lt;</span><span class="keyword">void</span><span class="special">&gt;</span></code> specialization:
</p>
<p>
</p>
<pre class="programlisting"><span class="comment">// yield_handler&lt;void&gt; is like yield_handler&lt;T&gt; without value_. In fact it's</span>
<span class="comment">// just like yield_handler_base.</span>
<span class="keyword">template</span><span class="special">&lt;&gt;</span>
<span class="keyword">class</span> <span class="identifier">yield_handler</span><span class="special">&lt;</span> <span class="keyword">void</span> <span class="special">&gt;:</span> <span class="keyword">public</span> <span class="identifier">yield_handler_base</span> <span class="special">{</span>
<span class="keyword">public</span><span class="special">:</span>
<span class="keyword">explicit</span> <span class="identifier">yield_handler</span><span class="special">(</span> <span class="identifier">yield_t</span> <span class="keyword">const</span><span class="special">&amp;</span> <span class="identifier">y</span><span class="special">)</span> <span class="special">:</span>
<span class="identifier">yield_handler_base</span><span class="special">{</span> <span class="identifier">y</span> <span class="special">}</span> <span class="special">{</span>
<span class="special">}</span>
<span class="comment">// nullary completion callback</span>
<span class="keyword">void</span> <span class="keyword">operator</span><span class="special">()()</span> <span class="special">{</span>
<span class="special">(</span> <span class="special">*</span> <span class="keyword">this</span><span class="special">)(</span> <span class="identifier">boost</span><span class="special">::</span><span class="identifier">system</span><span class="special">::</span><span class="identifier">error_code</span><span class="special">()</span> <span class="special">);</span>
<span class="special">}</span>
<span class="comment">// inherit operator()(error_code) overload from base class</span>
<span class="keyword">using</span> <span class="identifier">yield_handler_base</span><span class="special">::</span><span class="keyword">operator</span><span class="special">();</span>
<span class="special">};</span>
</pre>
<p>
</p>
<p>
<code class="computeroutput"><span class="identifier">async_something</span><span class="special">()</span></code>,
having consulted the <code class="computeroutput"><span class="identifier">handler_type</span><span class="special">&lt;&gt;</span></code> traits specialization, instantiates
a <code class="computeroutput"><span class="identifier">yield_handler</span><span class="special">&lt;</span><span class="keyword">void</span><span class="special">&gt;</span></code> to
be passed as the actual callback for the async operation. <code class="computeroutput"><span class="identifier">yield_handler</span></code>&#8217;s
constructor accepts the <code class="computeroutput"><span class="identifier">yield_t</span></code>
instance (the <code class="computeroutput"><span class="identifier">yield</span></code> object
passed to the async function) and passes it along to <code class="computeroutput"><span class="identifier">yield_handler_base</span></code>:
</p>
<p>
</p>
<pre class="programlisting"><span class="comment">// This class encapsulates common elements between yield_handler&lt;T&gt; (capturing</span>
<span class="comment">// a value to return from asio async function) and yield_handler&lt;void&gt; (no</span>
<span class="comment">// such value). See yield_handler&lt;T&gt; and its &lt;void&gt; specialization below. Both</span>
<span class="comment">// yield_handler&lt;T&gt; and yield_handler&lt;void&gt; are passed by value through</span>
<span class="comment">// various layers of asio functions. In other words, they're potentially</span>
<span class="comment">// copied multiple times. So key data such as the yield_completion instance</span>
<span class="comment">// must be stored in our async_result&lt;yield_handler&lt;&gt;&gt; specialization, which</span>
<span class="comment">// should be instantiated only once.</span>
<span class="keyword">class</span> <span class="identifier">yield_handler_base</span> <span class="special">{</span>
<span class="keyword">public</span><span class="special">:</span>
<span class="identifier">yield_handler_base</span><span class="special">(</span> <span class="identifier">yield_t</span> <span class="keyword">const</span><span class="special">&amp;</span> <span class="identifier">y</span><span class="special">)</span> <span class="special">:</span>
<span class="comment">// capture the context* associated with the running fiber</span>
<span class="identifier">ctx_</span><span class="special">{</span> <span class="identifier">boost</span><span class="special">::</span><span class="identifier">fibers</span><span class="special">::</span><span class="identifier">context</span><span class="special">::</span><span class="identifier">active</span><span class="special">()</span> <span class="special">},</span>
<span class="comment">// capture the passed yield_t</span>
<span class="identifier">yt_</span><span class="special">{</span> <span class="identifier">y</span> <span class="special">}</span> <span class="special">{</span>
<span class="special">}</span>
<span class="comment">// completion callback passing only (error_code)</span>
<span class="keyword">void</span> <span class="keyword">operator</span><span class="special">()(</span> <span class="identifier">boost</span><span class="special">::</span><span class="identifier">system</span><span class="special">::</span><span class="identifier">error_code</span> <span class="keyword">const</span><span class="special">&amp;</span> <span class="identifier">ec</span><span class="special">)</span> <span class="special">{</span>
<span class="identifier">BOOST_ASSERT_MSG</span><span class="special">(</span> <span class="identifier">ycomp_</span><span class="special">,</span>
<span class="string">"Must inject yield_completion* "</span>
<span class="string">"before calling yield_handler_base::operator()()"</span><span class="special">);</span>
<span class="identifier">BOOST_ASSERT_MSG</span><span class="special">(</span> <span class="identifier">yt_</span><span class="special">.</span><span class="identifier">ec_</span><span class="special">,</span>
<span class="string">"Must inject boost::system::error_code* "</span>
<span class="string">"before calling yield_handler_base::operator()()"</span><span class="special">);</span>
<span class="comment">// If originating fiber is busy testing completed_ flag, wait until it</span>
<span class="comment">// has observed (! completed_).</span>
<span class="identifier">yield_completion</span><span class="special">::</span><span class="identifier">lock_t</span> <span class="identifier">lk</span><span class="special">{</span> <span class="identifier">ycomp_</span><span class="special">-&gt;</span><span class="identifier">mtx_</span> <span class="special">};</span>
<span class="comment">// Notify a subsequent yield_completion::wait() call that it need not</span>
<span class="comment">// suspend.</span>
<span class="identifier">ycomp_</span><span class="special">-&gt;</span><span class="identifier">completed_</span> <span class="special">=</span> <span class="keyword">true</span><span class="special">;</span>
<span class="comment">// set the error_code bound by yield_t</span>
<span class="special">*</span> <span class="identifier">yt_</span><span class="special">.</span><span class="identifier">ec_</span> <span class="special">=</span> <span class="identifier">ec</span><span class="special">;</span>
<span class="comment">// If ctx_ is still active, e.g. because the async operation</span>
<span class="comment">// immediately called its callback (this method!) before the asio</span>
<span class="comment">// async function called async_result_base::get(), we must not set it</span>
<span class="comment">// ready.</span>
<span class="keyword">if</span> <span class="special">(</span> <span class="identifier">fibers</span><span class="special">::</span><span class="identifier">context</span><span class="special">::</span><span class="identifier">active</span><span class="special">()</span> <span class="special">!=</span> <span class="identifier">ctx_</span> <span class="special">)</span> <span class="special">{</span>
<span class="comment">// wake the fiber</span>
<span class="identifier">fibers</span><span class="special">::</span><span class="identifier">context</span><span class="special">::</span><span class="identifier">active</span><span class="special">()-&gt;</span><span class="identifier">set_ready</span><span class="special">(</span> <span class="identifier">ctx_</span><span class="special">);</span>
<span class="special">}</span>
<span class="special">}</span>
<span class="comment">//private:</span>
<span class="identifier">boost</span><span class="special">::</span><span class="identifier">fibers</span><span class="special">::</span><span class="identifier">context</span> <span class="special">*</span> <span class="identifier">ctx_</span><span class="special">;</span>
<span class="identifier">yield_t</span> <span class="identifier">yt_</span><span class="special">;</span>
<span class="comment">// We depend on this pointer to yield_completion, which will be injected</span>
<span class="comment">// by async_result.</span>
<span class="identifier">yield_completion</span> <span class="special">*</span> <span class="identifier">ycomp_</span><span class="special">{</span> <span class="keyword">nullptr</span> <span class="special">};</span>
<span class="special">};</span>
</pre>
<p>
</p>
<p>
<code class="computeroutput"><span class="identifier">yield_handler_base</span></code> stores
a copy of the <code class="computeroutput"><span class="identifier">yield_t</span></code> instance
&#8212; which, as shown above, contains only an <code class="computeroutput"><span class="identifier">error_code</span><span class="special">*</span></code>. It also captures the <a class="link" href="../scheduling.html#class_context"><code class="computeroutput">context</code></a>*
for the currently-running fiber by calling <a class="link" href="../scheduling.html#context_active"><code class="computeroutput">context::active()</code></a>.
</p>
<p>
You will notice that <code class="computeroutput"><span class="identifier">yield_handler_base</span></code>
has one more data member (<code class="computeroutput"><span class="identifier">ycomp_</span></code>)
that is initialized to <code class="computeroutput"><span class="keyword">nullptr</span></code>
by its constructor &#8212; though its <code class="computeroutput"><span class="keyword">operator</span><span class="special">()()</span></code> method relies on <code class="computeroutput"><span class="identifier">ycomp_</span></code>
being non-null. More on this in a moment.
</p>
<p>
Having constructed the <code class="computeroutput"><span class="identifier">yield_handler</span><span class="special">&lt;</span><span class="keyword">void</span><span class="special">&gt;</span></code>
instance, <code class="computeroutput"><span class="identifier">async_something</span><span class="special">()</span></code> goes on to construct an <code class="computeroutput"><span class="identifier">async_result</span></code>
specialized for the <code class="computeroutput"><span class="identifier">handler_type</span><span class="special">&lt;&gt;::</span><span class="identifier">type</span></code>:
in this case, <code class="computeroutput"><span class="identifier">async_result</span><span class="special">&lt;</span><span class="identifier">yield_handler</span><span class="special">&lt;</span><span class="keyword">void</span><span class="special">&gt;&gt;</span></code>.
It passes the <code class="computeroutput"><span class="identifier">yield_handler</span><span class="special">&lt;</span><span class="keyword">void</span><span class="special">&gt;</span></code>
instance to the new <code class="computeroutput"><span class="identifier">async_result</span></code>
instance.
</p>
<p>
</p>
<pre class="programlisting"><span class="comment">// Without the need to handle a passed value, our yield_handler&lt;void&gt;</span>
<span class="comment">// specialization is just like async_result_base.</span>
<span class="keyword">template</span><span class="special">&lt;&gt;</span>
<span class="keyword">class</span> <span class="identifier">async_result</span><span class="special">&lt;</span> <span class="identifier">boost</span><span class="special">::</span><span class="identifier">fibers</span><span class="special">::</span><span class="identifier">asio</span><span class="special">::</span><span class="identifier">detail</span><span class="special">::</span><span class="identifier">yield_handler</span><span class="special">&lt;</span> <span class="keyword">void</span> <span class="special">&gt;</span> <span class="special">&gt;</span> <span class="special">:</span>
<span class="keyword">public</span> <span class="identifier">boost</span><span class="special">::</span><span class="identifier">fibers</span><span class="special">::</span><span class="identifier">asio</span><span class="special">::</span><span class="identifier">detail</span><span class="special">::</span><span class="identifier">async_result_base</span> <span class="special">{</span>
<span class="keyword">public</span><span class="special">:</span>
<span class="keyword">typedef</span> <span class="keyword">void</span> <span class="identifier">type</span><span class="special">;</span>
<span class="keyword">explicit</span> <span class="identifier">async_result</span><span class="special">(</span> <span class="identifier">boost</span><span class="special">::</span><span class="identifier">fibers</span><span class="special">::</span><span class="identifier">asio</span><span class="special">::</span><span class="identifier">detail</span><span class="special">::</span><span class="identifier">yield_handler</span><span class="special">&lt;</span> <span class="keyword">void</span> <span class="special">&gt;</span> <span class="special">&amp;</span> <span class="identifier">h</span><span class="special">):</span>
<span class="identifier">boost</span><span class="special">::</span><span class="identifier">fibers</span><span class="special">::</span><span class="identifier">asio</span><span class="special">::</span><span class="identifier">detail</span><span class="special">::</span><span class="identifier">async_result_base</span><span class="special">{</span> <span class="identifier">h</span> <span class="special">}</span> <span class="special">{</span>
<span class="special">}</span>
<span class="special">};</span>
</pre>
<p>
</p>
<p>
Naturally that leads us straight to <code class="computeroutput"><span class="identifier">async_result_base</span></code>:
</p>
<p>
</p>
<pre class="programlisting"><span class="comment">// Factor out commonality between async_result&lt;yield_handler&lt;T&gt;&gt; and</span>
<span class="comment">// async_result&lt;yield_handler&lt;void&gt;&gt;</span>
<span class="keyword">class</span> <span class="identifier">async_result_base</span> <span class="special">{</span>
<span class="keyword">public</span><span class="special">:</span>
<span class="keyword">explicit</span> <span class="identifier">async_result_base</span><span class="special">(</span> <span class="identifier">yield_handler_base</span> <span class="special">&amp;</span> <span class="identifier">h</span><span class="special">)</span> <span class="special">{</span>
<span class="comment">// Inject ptr to our yield_completion instance into this</span>
<span class="comment">// yield_handler&lt;&gt;.</span>
<span class="identifier">h</span><span class="special">.</span><span class="identifier">ycomp_</span> <span class="special">=</span> <span class="special">&amp;</span> <span class="keyword">this</span><span class="special">-&gt;</span><span class="identifier">ycomp_</span><span class="special">;</span>
<span class="comment">// if yield_t didn't bind an error_code, make yield_handler_base's</span>
<span class="comment">// error_code* point to an error_code local to this object so</span>
<span class="comment">// yield_handler_base::operator() can unconditionally store through</span>
<span class="comment">// its error_code*</span>
<span class="keyword">if</span> <span class="special">(</span> <span class="special">!</span> <span class="identifier">h</span><span class="special">.</span><span class="identifier">yt_</span><span class="special">.</span><span class="identifier">ec_</span><span class="special">)</span> <span class="special">{</span>
<span class="identifier">h</span><span class="special">.</span><span class="identifier">yt_</span><span class="special">.</span><span class="identifier">ec_</span> <span class="special">=</span> <span class="special">&amp;</span> <span class="identifier">ec_</span><span class="special">;</span>
<span class="special">}</span>
<span class="special">}</span>
<span class="keyword">void</span> <span class="identifier">get</span><span class="special">()</span> <span class="special">{</span>
<span class="comment">// Unless yield_handler_base::operator() has already been called,</span>
<span class="comment">// suspend the calling fiber until that call.</span>
<span class="identifier">ycomp_</span><span class="special">.</span><span class="identifier">wait</span><span class="special">();</span>
<span class="comment">// The only way our own ec_ member could have a non-default value is</span>
<span class="comment">// if our yield_handler did not have a bound error_code AND the</span>
<span class="comment">// completion callback passed a non-default error_code.</span>
<span class="keyword">if</span> <span class="special">(</span> <span class="identifier">ec_</span><span class="special">)</span> <span class="special">{</span>
<span class="identifier">throw_exception</span><span class="special">(</span> <span class="identifier">boost</span><span class="special">::</span><span class="identifier">system</span><span class="special">::</span><span class="identifier">system_error</span><span class="special">{</span> <span class="identifier">ec_</span> <span class="special">}</span> <span class="special">);</span>
<span class="special">}</span>
<span class="special">}</span>
<span class="keyword">private</span><span class="special">:</span>
<span class="comment">// If yield_t does not bind an error_code instance, store into here.</span>
<span class="identifier">boost</span><span class="special">::</span><span class="identifier">system</span><span class="special">::</span><span class="identifier">error_code</span> <span class="identifier">ec_</span><span class="special">{};</span>
<span class="comment">// async_result_base owns the yield_completion because, unlike</span>
<span class="comment">// yield_handler&lt;&gt;, async_result&lt;&gt; is only instantiated once.</span>
<span class="identifier">yield_completion</span> <span class="identifier">ycomp_</span><span class="special">{};</span>
<span class="special">};</span>
</pre>
<p>
</p>
<p>
This is how <code class="computeroutput"><span class="identifier">yield_handler_base</span><span class="special">::</span><span class="identifier">ycomp_</span></code>
becomes non-null: <code class="computeroutput"><span class="identifier">async_result_base</span></code>&#8217;s
constructor injects a pointer back to its own <code class="computeroutput"><span class="identifier">yield_completion</span></code>
member.
</p>
<p>
Recall that the canonical <code class="computeroutput"><span class="identifier">yield_t</span></code>
instance <code class="computeroutput"><span class="identifier">yield</span></code> initializes
its <code class="computeroutput"><span class="identifier">error_code</span><span class="special">*</span></code>
member <code class="computeroutput"><span class="identifier">ec_</span></code> to <code class="computeroutput"><span class="keyword">nullptr</span></code>. If this instance is passed to <code class="computeroutput"><span class="identifier">async_something</span><span class="special">()</span></code>
(<code class="computeroutput"><span class="identifier">ec_</span></code> is still <code class="computeroutput"><span class="keyword">nullptr</span></code>), the copy stored in <code class="computeroutput"><span class="identifier">yield_handler_base</span></code> will likewise have null
<code class="computeroutput"><span class="identifier">ec_</span></code>. <code class="computeroutput"><span class="identifier">async_result_base</span></code>&#8217;s
constructor sets <code class="computeroutput"><span class="identifier">yield_handler_base</span></code>&#8217;s
<code class="computeroutput"><span class="identifier">yield_t</span></code>&#8217;s <code class="computeroutput"><span class="identifier">ec_</span></code>
member to point to its own <code class="computeroutput"><span class="identifier">error_code</span></code>
member.
</p>
<p>
The stage is now set. <code class="computeroutput"><span class="identifier">async_something</span><span class="special">()</span></code> initiates the actual async operation, arranging
to call its <code class="computeroutput"><span class="identifier">yield_handler</span><span class="special">&lt;</span><span class="keyword">void</span><span class="special">&gt;</span></code>
instance on completion. Let&#8217;s say, for the sake of argument, that the actual
async operation&#8217;s callback has signature <code class="computeroutput"><span class="keyword">void</span><span class="special">(</span><span class="identifier">error_code</span><span class="special">)</span></code>.
</p>
<p>
But since it&#8217;s an async operation, control returns at once to <code class="computeroutput"><span class="identifier">async_something</span><span class="special">()</span></code>.
<code class="computeroutput"><span class="identifier">async_something</span><span class="special">()</span></code>
calls <code class="computeroutput"><span class="identifier">async_result</span><span class="special">&lt;</span><span class="identifier">yield_handler</span><span class="special">&lt;</span><span class="keyword">void</span><span class="special">&gt;&gt;::</span><span class="identifier">get</span><span class="special">()</span></code>,
and will return its return value.
</p>
<p>
<code class="computeroutput"><span class="identifier">async_result</span><span class="special">&lt;</span><span class="identifier">yield_handler</span><span class="special">&lt;</span><span class="keyword">void</span><span class="special">&gt;&gt;::</span><span class="identifier">get</span><span class="special">()</span></code> inherits
<code class="computeroutput"><span class="identifier">async_result_base</span><span class="special">::</span><span class="identifier">get</span><span class="special">()</span></code>.
</p>
<p>
<code class="computeroutput"><span class="identifier">async_result_base</span><span class="special">::</span><span class="identifier">get</span><span class="special">()</span></code> immediately
calls <code class="computeroutput"><span class="identifier">yield_completion</span><span class="special">::</span><span class="identifier">wait</span><span class="special">()</span></code>.
</p>
<p>
</p>
<pre class="programlisting"><span class="comment">// Bundle a completion bool flag with a spinlock to protect it.</span>
<span class="keyword">struct</span> <span class="identifier">yield_completion</span> <span class="special">{</span>
<span class="keyword">typedef</span> <span class="identifier">fibers</span><span class="special">::</span><span class="identifier">detail</span><span class="special">::</span><span class="identifier">spinlock</span> <span class="identifier">mutex_t</span><span class="special">;</span>
<span class="keyword">typedef</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">unique_lock</span><span class="special">&lt;</span> <span class="identifier">mutex_t</span> <span class="special">&gt;</span> <span class="identifier">lock_t</span><span class="special">;</span>
<span class="identifier">mutex_t</span> <span class="identifier">mtx_</span><span class="special">{};</span>
<span class="keyword">bool</span> <span class="identifier">completed_</span><span class="special">{</span> <span class="keyword">false</span> <span class="special">};</span>
<span class="keyword">void</span> <span class="identifier">wait</span><span class="special">()</span> <span class="special">{</span>
<span class="comment">// yield_handler_base::operator()() will set completed_ true and</span>
<span class="comment">// attempt to wake a suspended fiber. It would be Bad if that call</span>
<span class="comment">// happened between our detecting (! completed_) and suspending.</span>
<span class="identifier">lock_t</span> <span class="identifier">lk</span><span class="special">{</span> <span class="identifier">mtx_</span> <span class="special">};</span>
<span class="comment">// If completed_ is already set, we're done here: don't suspend.</span>
<span class="keyword">if</span> <span class="special">(</span> <span class="special">!</span> <span class="identifier">completed_</span><span class="special">)</span> <span class="special">{</span>
<span class="comment">// suspend(unique_lock&lt;spinlock&gt;) unlocks the lock in the act of</span>
<span class="comment">// resuming another fiber</span>
<span class="identifier">fibers</span><span class="special">::</span><span class="identifier">context</span><span class="special">::</span><span class="identifier">active</span><span class="special">()-&gt;</span><span class="identifier">suspend</span><span class="special">(</span> <span class="identifier">lk</span><span class="special">);</span>
<span class="special">}</span>
<span class="special">}</span>
<span class="special">};</span>
</pre>
<p>
</p>
<p>
Supposing that the pending async operation has not yet completed, <code class="computeroutput"><span class="identifier">yield_completion</span><span class="special">::</span><span class="identifier">completed_</span></code> will still be <code class="computeroutput"><span class="keyword">false</span></code>, and <code class="computeroutput"><span class="identifier">wait</span><span class="special">()</span></code> will call <a class="link" href="../scheduling.html#context_suspend"><code class="computeroutput">context::suspend()</code></a> on
the currently-running fiber.
</p>
<p>
Other fibers will now have a chance to run.
</p>
<p>
Some time later, the async operation completes. It calls <code class="computeroutput"><span class="identifier">yield_handler</span><span class="special">&lt;</span><span class="keyword">void</span><span class="special">&gt;::</span><span class="keyword">operator</span><span class="special">()(</span><span class="identifier">error_code</span> <span class="keyword">const</span><span class="special">&amp;)</span></code> with an <code class="computeroutput"><span class="identifier">error_code</span></code>
indicating either success or failure. We&#8217;ll consider both cases.
</p>
<p>
<code class="computeroutput"><span class="identifier">yield_handler</span><span class="special">&lt;</span><span class="keyword">void</span><span class="special">&gt;</span></code> explicitly
inherits <code class="computeroutput"><span class="keyword">operator</span><span class="special">()(</span><span class="identifier">error_code</span> <span class="keyword">const</span><span class="special">&amp;)</span></code> from <code class="computeroutput"><span class="identifier">yield_handler_base</span></code>.
</p>
<p>
<code class="computeroutput"><span class="identifier">yield_handler_base</span><span class="special">::</span><span class="keyword">operator</span><span class="special">()(</span><span class="identifier">error_code</span> <span class="keyword">const</span><span class="special">&amp;)</span></code> first sets <code class="computeroutput"><span class="identifier">yield_completion</span><span class="special">::</span><span class="identifier">completed_</span></code>
<code class="computeroutput"><span class="keyword">true</span></code>. This way, if <code class="computeroutput"><span class="identifier">async_something</span><span class="special">()</span></code>&#8217;s
async operation completes immediately &#8212; if <code class="computeroutput"><span class="identifier">yield_handler_base</span><span class="special">::</span><span class="keyword">operator</span><span class="special">()</span></code> is called even before <code class="computeroutput"><span class="identifier">async_result_base</span><span class="special">::</span><span class="identifier">get</span><span class="special">()</span></code>
&#8212; the calling fiber will <span class="emphasis"><em>not</em></span> suspend.
</p>
<p>
The actual <code class="computeroutput"><span class="identifier">error_code</span></code> produced
by the async operation is then stored through the stored <code class="computeroutput"><span class="identifier">yield_t</span><span class="special">::</span><span class="identifier">ec_</span></code> pointer.
If <code class="computeroutput"><span class="identifier">async_something</span><span class="special">()</span></code>&#8217;s
caller used (e.g.) <code class="computeroutput"><span class="identifier">yield</span><span class="special">[</span><span class="identifier">my_ec</span><span class="special">]</span></code> to bind a local <code class="computeroutput"><span class="identifier">error_code</span></code>
instance, the actual <code class="computeroutput"><span class="identifier">error_code</span></code>
value is stored into the caller&#8217;s variable. Otherwise, it is stored into
<code class="computeroutput"><span class="identifier">async_result_base</span><span class="special">::</span><span class="identifier">ec_</span></code>.
</p>
<p>
If the stored fiber context <code class="computeroutput"><span class="identifier">yield_handler_base</span><span class="special">::</span><span class="identifier">ctx_</span></code>
is not already running, it is marked as ready to run by passing it to <a class="link" href="../scheduling.html#context_set_ready"><code class="computeroutput">context::set_ready()</code></a>.
Control then returns from <code class="computeroutput"><span class="identifier">yield_handler_base</span><span class="special">::</span><span class="keyword">operator</span><span class="special">()</span></code>: the callback is done.
</p>
<p>
In due course, that fiber is resumed. Control returns from <a class="link" href="../scheduling.html#context_suspend"><code class="computeroutput">context::suspend()</code></a> to
<code class="computeroutput"><span class="identifier">yield_completion</span><span class="special">::</span><span class="identifier">wait</span><span class="special">()</span></code>,
which returns to <code class="computeroutput"><span class="identifier">async_result_base</span><span class="special">::</span><span class="identifier">get</span><span class="special">()</span></code>.
</p>
<div class="itemizedlist"><ul class="itemizedlist" type="disc">
<li class="listitem">
If the original caller passed <code class="computeroutput"><span class="identifier">yield</span><span class="special">[</span><span class="identifier">my_ec</span><span class="special">]</span></code> to <code class="computeroutput"><span class="identifier">async_something</span><span class="special">()</span></code> to bind a local <code class="computeroutput"><span class="identifier">error_code</span></code>
instance, then <code class="computeroutput"><span class="identifier">yield_handler_base</span><span class="special">::</span><span class="keyword">operator</span><span class="special">()</span></code> stored its <code class="computeroutput"><span class="identifier">error_code</span></code>
to the caller&#8217;s <code class="computeroutput"><span class="identifier">my_ec</span></code>
instance, leaving <code class="computeroutput"><span class="identifier">async_result_base</span><span class="special">::</span><span class="identifier">ec_</span></code>
initialized to success.
</li>
<li class="listitem">
If the original caller passed <code class="computeroutput"><span class="identifier">yield</span></code>
to <code class="computeroutput"><span class="identifier">async_something</span><span class="special">()</span></code>
without binding a local <code class="computeroutput"><span class="identifier">error_code</span></code>
variable, then <code class="computeroutput"><span class="identifier">yield_handler_base</span><span class="special">::</span><span class="keyword">operator</span><span class="special">()</span></code> stored its <code class="computeroutput"><span class="identifier">error_code</span></code>
into <code class="computeroutput"><span class="identifier">async_result_base</span><span class="special">::</span><span class="identifier">ec_</span></code>.
If in fact that <code class="computeroutput"><span class="identifier">error_code</span></code>
is success, then all is well.
</li>
<li class="listitem">
Otherwise &#8212; the original caller did not bind a local <code class="computeroutput"><span class="identifier">error_code</span></code>
and <code class="computeroutput"><span class="identifier">yield_handler_base</span><span class="special">::</span><span class="keyword">operator</span><span class="special">()</span></code> was called with an <code class="computeroutput"><span class="identifier">error_code</span></code>
indicating error &#8212; <code class="computeroutput"><span class="identifier">async_result_base</span><span class="special">::</span><span class="identifier">get</span><span class="special">()</span></code> throws <code class="computeroutput"><span class="identifier">system_error</span></code>
with that <code class="computeroutput"><span class="identifier">error_code</span></code>.
</li>
</ul></div>
<p>
The case in which <code class="computeroutput"><span class="identifier">async_something</span><span class="special">()</span></code>&#8217;s completion callback has signature <code class="computeroutput"><span class="keyword">void</span><span class="special">()</span></code> is
similar. <code class="computeroutput"><span class="identifier">yield_handler</span><span class="special">&lt;</span><span class="keyword">void</span><span class="special">&gt;::</span><span class="keyword">operator</span><span class="special">()()</span></code>
invokes the machinery above with a <span class="quote">&#8220;<span class="quote">success</span>&#8221;</span> <code class="computeroutput"><span class="identifier">error_code</span></code>.
</p>
<p>
A completion callback with signature <code class="computeroutput"><span class="keyword">void</span><span class="special">(</span><span class="identifier">error_code</span><span class="special">,</span> <span class="identifier">T</span><span class="special">)</span></code>
(that is: in addition to <code class="computeroutput"><span class="identifier">error_code</span></code>,
callback receives some data item) is handled somewhat differently. For this
kind of signature, <code class="computeroutput"><span class="identifier">handler_type</span><span class="special">&lt;&gt;::</span><span class="identifier">type</span></code>
specifies <code class="computeroutput"><span class="identifier">yield_handler</span><span class="special">&lt;</span><span class="identifier">T</span><span class="special">&gt;</span></code> (for
<code class="computeroutput"><span class="identifier">T</span></code> other than <code class="computeroutput"><span class="keyword">void</span></code>).
</p>
<p>
A <code class="computeroutput"><span class="identifier">yield_handler</span><span class="special">&lt;</span><span class="identifier">T</span><span class="special">&gt;</span></code> reserves
a <code class="computeroutput"><span class="identifier">value_</span></code> pointer to a value
of type <code class="computeroutput"><span class="identifier">T</span></code>:
</p>
<p>
</p>
<pre class="programlisting"><span class="comment">// asio uses handler_type&lt;completion token type, signature&gt;::type to decide</span>
<span class="comment">// what to instantiate as the actual handler. Below, we specialize</span>
<span class="comment">// handler_type&lt; yield_t, ... &gt; to indicate yield_handler&lt;&gt;. So when you pass</span>
<span class="comment">// an instance of yield_t as an asio completion token, asio selects</span>
<span class="comment">// yield_handler&lt;&gt; as the actual handler class.</span>
<span class="keyword">template</span><span class="special">&lt;</span> <span class="keyword">typename</span> <span class="identifier">T</span> <span class="special">&gt;</span>
<span class="keyword">class</span> <span class="identifier">yield_handler</span><span class="special">:</span> <span class="keyword">public</span> <span class="identifier">yield_handler_base</span> <span class="special">{</span>
<span class="keyword">public</span><span class="special">:</span>
<span class="comment">// asio passes the completion token to the handler constructor</span>
<span class="keyword">explicit</span> <span class="identifier">yield_handler</span><span class="special">(</span> <span class="identifier">yield_t</span> <span class="keyword">const</span><span class="special">&amp;</span> <span class="identifier">y</span><span class="special">)</span> <span class="special">:</span>
<span class="identifier">yield_handler_base</span><span class="special">{</span> <span class="identifier">y</span> <span class="special">}</span> <span class="special">{</span>
<span class="special">}</span>
<span class="comment">// completion callback passing only value (T)</span>
<span class="keyword">void</span> <span class="keyword">operator</span><span class="special">()(</span> <span class="identifier">T</span> <span class="identifier">t</span><span class="special">)</span> <span class="special">{</span>
<span class="comment">// just like callback passing success error_code</span>
<span class="special">(*</span><span class="keyword">this</span><span class="special">)(</span> <span class="identifier">boost</span><span class="special">::</span><span class="identifier">system</span><span class="special">::</span><span class="identifier">error_code</span><span class="special">(),</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">move</span><span class="special">(</span><span class="identifier">t</span><span class="special">)</span> <span class="special">);</span>
<span class="special">}</span>
<span class="comment">// completion callback passing (error_code, T)</span>
<span class="keyword">void</span> <span class="keyword">operator</span><span class="special">()(</span> <span class="identifier">boost</span><span class="special">::</span><span class="identifier">system</span><span class="special">::</span><span class="identifier">error_code</span> <span class="keyword">const</span><span class="special">&amp;</span> <span class="identifier">ec</span><span class="special">,</span> <span class="identifier">T</span> <span class="identifier">t</span><span class="special">)</span> <span class="special">{</span>
<span class="identifier">BOOST_ASSERT_MSG</span><span class="special">(</span> <span class="identifier">value_</span><span class="special">,</span>
<span class="string">"Must inject value ptr "</span>
<span class="string">"before caling yield_handler&lt;T&gt;::operator()()"</span><span class="special">);</span>
<span class="comment">// move the value to async_result&lt;&gt; instance BEFORE waking up a</span>
<span class="comment">// suspended fiber</span>
<span class="special">*</span> <span class="identifier">value_</span> <span class="special">=</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">move</span><span class="special">(</span> <span class="identifier">t</span><span class="special">);</span>
<span class="comment">// forward the call to base-class completion handler</span>
<span class="identifier">yield_handler_base</span><span class="special">::</span><span class="keyword">operator</span><span class="special">()(</span> <span class="identifier">ec</span><span class="special">);</span>
<span class="special">}</span>
<span class="comment">//private:</span>
<span class="comment">// pointer to destination for eventual value</span>
<span class="comment">// this must be injected by async_result before operator()() is called</span>
<span class="identifier">T</span> <span class="special">*</span> <span class="identifier">value_</span><span class="special">{</span> <span class="keyword">nullptr</span> <span class="special">};</span>
<span class="special">};</span>
</pre>
<p>
</p>
<p>
This pointer is initialized to <code class="computeroutput"><span class="keyword">nullptr</span></code>.
</p>
<p>
When <code class="computeroutput"><span class="identifier">async_something</span><span class="special">()</span></code>
instantiates <code class="computeroutput"><span class="identifier">async_result</span><span class="special">&lt;</span><span class="identifier">yield_handler</span><span class="special">&lt;</span><span class="identifier">T</span><span class="special">&gt;&gt;</span></code>:
</p>
<p>
</p>
<pre class="programlisting"><span class="comment">// asio constructs an async_result&lt;&gt; instance from the yield_handler specified</span>
<span class="comment">// by handler_type&lt;&gt;::type. A particular asio async method constructs the</span>
<span class="comment">// yield_handler, constructs this async_result specialization from it, then</span>
<span class="comment">// returns the result of calling its get() method.</span>
<span class="keyword">template</span><span class="special">&lt;</span> <span class="keyword">typename</span> <span class="identifier">T</span> <span class="special">&gt;</span>
<span class="keyword">class</span> <span class="identifier">async_result</span><span class="special">&lt;</span> <span class="identifier">boost</span><span class="special">::</span><span class="identifier">fibers</span><span class="special">::</span><span class="identifier">asio</span><span class="special">::</span><span class="identifier">detail</span><span class="special">::</span><span class="identifier">yield_handler</span><span class="special">&lt;</span> <span class="identifier">T</span> <span class="special">&gt;</span> <span class="special">&gt;</span> <span class="special">:</span>
<span class="keyword">public</span> <span class="identifier">boost</span><span class="special">::</span><span class="identifier">fibers</span><span class="special">::</span><span class="identifier">asio</span><span class="special">::</span><span class="identifier">detail</span><span class="special">::</span><span class="identifier">async_result_base</span> <span class="special">{</span>
<span class="keyword">public</span><span class="special">:</span>
<span class="comment">// type returned by get()</span>
<span class="keyword">typedef</span> <span class="identifier">T</span> <span class="identifier">type</span><span class="special">;</span>
<span class="keyword">explicit</span> <span class="identifier">async_result</span><span class="special">(</span> <span class="identifier">boost</span><span class="special">::</span><span class="identifier">fibers</span><span class="special">::</span><span class="identifier">asio</span><span class="special">::</span><span class="identifier">detail</span><span class="special">::</span><span class="identifier">yield_handler</span><span class="special">&lt;</span> <span class="identifier">T</span> <span class="special">&gt;</span> <span class="special">&amp;</span> <span class="identifier">h</span><span class="special">)</span> <span class="special">:</span>
<span class="identifier">boost</span><span class="special">::</span><span class="identifier">fibers</span><span class="special">::</span><span class="identifier">asio</span><span class="special">::</span><span class="identifier">detail</span><span class="special">::</span><span class="identifier">async_result_base</span><span class="special">{</span> <span class="identifier">h</span> <span class="special">}</span> <span class="special">{</span>
<span class="comment">// Inject ptr to our value_ member into yield_handler&lt;&gt;: result will</span>
<span class="comment">// be stored here.</span>
<span class="identifier">h</span><span class="special">.</span><span class="identifier">value_</span> <span class="special">=</span> <span class="special">&amp;</span> <span class="identifier">value_</span><span class="special">;</span>
<span class="special">}</span>
<span class="comment">// asio async method returns result of calling get()</span>
<span class="identifier">type</span> <span class="identifier">get</span><span class="special">()</span> <span class="special">{</span>
<span class="identifier">boost</span><span class="special">::</span><span class="identifier">fibers</span><span class="special">::</span><span class="identifier">asio</span><span class="special">::</span><span class="identifier">detail</span><span class="special">::</span><span class="identifier">async_result_base</span><span class="special">::</span><span class="identifier">get</span><span class="special">();</span>
<span class="keyword">return</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">move</span><span class="special">(</span> <span class="identifier">value_</span><span class="special">);</span>
<span class="special">}</span>
<span class="keyword">private</span><span class="special">:</span>
<span class="identifier">type</span> <span class="identifier">value_</span><span class="special">{};</span>
<span class="special">};</span>
</pre>
<p>
</p>
<p>
this <code class="computeroutput"><span class="identifier">async_result</span><span class="special">&lt;&gt;</span></code>
specialization reserves a member of type <code class="computeroutput"><span class="identifier">T</span></code>
to receive the passed data item, and sets <code class="computeroutput"><span class="identifier">yield_handler</span><span class="special">&lt;</span><span class="identifier">T</span><span class="special">&gt;::</span><span class="identifier">value_</span></code> to point to its own data member.
</p>
<p>
<code class="computeroutput"><span class="identifier">async_result</span><span class="special">&lt;</span><span class="identifier">yield_handler</span><span class="special">&lt;</span><span class="identifier">T</span><span class="special">&gt;&gt;</span></code>
overrides <code class="computeroutput"><span class="identifier">get</span><span class="special">()</span></code>.
The override calls <code class="computeroutput"><span class="identifier">async_result_base</span><span class="special">::</span><span class="identifier">get</span><span class="special">()</span></code>,
so the calling fiber suspends as described above.
</p>
<p>
<code class="computeroutput"><span class="identifier">yield_handler</span><span class="special">&lt;</span><span class="identifier">T</span><span class="special">&gt;::</span><span class="keyword">operator</span><span class="special">()(</span><span class="identifier">error_code</span><span class="special">,</span> <span class="identifier">T</span><span class="special">)</span></code> stores
its passed <code class="computeroutput"><span class="identifier">T</span></code> value into
<code class="computeroutput"><span class="identifier">async_result</span><span class="special">&lt;</span><span class="identifier">yield_handler</span><span class="special">&lt;</span><span class="identifier">T</span><span class="special">&gt;&gt;::</span><span class="identifier">value_</span></code>.
</p>
<p>
Then it passes control to <code class="computeroutput"><span class="identifier">yield_handler_base</span><span class="special">::</span><span class="keyword">operator</span><span class="special">()(</span><span class="identifier">error_code</span><span class="special">)</span></code> to deal with waking the original fiber as
described above.
</p>
<p>
When <code class="computeroutput"><span class="identifier">async_result</span><span class="special">&lt;</span><span class="identifier">yield_handler</span><span class="special">&lt;</span><span class="identifier">T</span><span class="special">&gt;&gt;::</span><span class="identifier">get</span><span class="special">()</span></code> resumes,
it returns the stored <code class="computeroutput"><span class="identifier">value_</span></code>
to <code class="computeroutput"><span class="identifier">async_something</span><span class="special">()</span></code>
and ultimately to <code class="computeroutput"><span class="identifier">async_something</span><span class="special">()</span></code>&#8217;s caller.
</p>
<p>
The case of a callback signature <code class="computeroutput"><span class="keyword">void</span><span class="special">(</span><span class="identifier">T</span><span class="special">)</span></code>
is handled by having <code class="computeroutput"><span class="identifier">yield_handler</span><span class="special">&lt;</span><span class="identifier">T</span><span class="special">&gt;::</span><span class="keyword">operator</span><span class="special">()(</span><span class="identifier">T</span><span class="special">)</span></code> engage
the <code class="computeroutput"><span class="keyword">void</span><span class="special">(</span><span class="identifier">error_code</span><span class="special">,</span> <span class="identifier">T</span><span class="special">)</span></code> machinery,
passing a <span class="quote">&#8220;<span class="quote">success</span>&#8221;</span> <code class="computeroutput"><span class="identifier">error_code</span></code>.
</p>
<p>
The source code above is found in <a href="../../../../examples/asio/yield.hpp" target="_top">yield.hpp</a>
and <a href="../../../../examples/asio/detail/yield.hpp" target="_top">detail/yield.hpp</a>.
</p>
<div class="footnotes">
<br><hr width="100" align="left">
<div class="footnote"><p><sup>[<a name="ftn.fiber.callbacks.then_there_s____boost_asio__.f0" href="#fiber.callbacks.then_there_s____boost_asio__.f0" class="para">4</a>] </sup>
This mechanism has been proposed as a conventional way to allow the caller
of an arbitrary async function to specify completion handling: <a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2014/n4045.pdf" target="_top">N4045</a>.
</p></div>
<div class="footnote"><p><sup>[<a name="ftn.fiber.callbacks.then_there_s____boost_asio__.f1" href="#fiber.callbacks.then_there_s____boost_asio__.f1" class="para">5</a>] </sup>
per <a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2014/n4045.pdf" target="_top">N4045</a>
</p></div>
</div>
</div>
<table xmlns:rev="http://www.cs.rpi.edu/~gregod/boost/tools/doc/revision" width="100%"><tr>
<td align="left"></td>
<td align="right"><div class="copyright-footer">Copyright &#169; 2013 Oliver Kowalke<p>
Distributed under the Boost Software License, Version 1.0. (See accompanying
file LICENSE_1_0.txt or copy at <a href="http://www.boost.org/LICENSE_1_0.txt" target="_top">http://www.boost.org/LICENSE_1_0.txt</a>)
</p>
</div></td>
</tr></table>
<hr>
<div class="spirit-nav">
<a accesskey="p" href="success_error_virtual_methods.html"><img src="../../../../../../doc/src/images/prev.png" alt="Prev"></a><a accesskey="u" href="../callbacks.html"><img src="../../../../../../doc/src/images/up.png" alt="Up"></a><a accesskey="h" href="../../index.html"><img src="../../../../../../doc/src/images/home.png" alt="Home"></a><a accesskey="n" href="../nonblocking.html"><img src="../../../../../../doc/src/images/next.png" alt="Next"></a>
</div>
</body>
</html>

View File

@@ -32,7 +32,7 @@
</h4>
<p>
As noted in the <a class="link" href="scheduling.html#scheduling">Scheduling</a> section, by default
<span class="bold"><strong>Boost.Fiber</strong></span> uses its own <a class="link" href="scheduling.html#class_round_robin"> <code class="computeroutput">round_robin</code></a> scheduler
<span class="bold"><strong>Boost.Fiber</strong></span> uses its own <a class="link" href="scheduling.html#class_round_robin"><code class="computeroutput">round_robin</code></a> scheduler
for each thread. To control the way <span class="bold"><strong>Boost.Fiber</strong></span>
schedules ready fibers on a particular thread, in general you must follow several
steps. This section discusses those steps, whereas <a class="link" href="scheduling.html#scheduling">Scheduling</a>
@@ -61,16 +61,16 @@
</h4>
<p>
The first essential point is that we must associate an integer priority with
each fiber.<sup>[<a name="fiber.custom.f0" href="#ftn.fiber.custom.f0" class="footnote">10</a>]</sup>
each fiber.<sup>[<a name="fiber.custom.f0" href="#ftn.fiber.custom.f0" class="footnote">9</a>]</sup>
</p>
<p>
One might suggest deriving a custom <a class="link" href="fiber_mgmt/fiber.html#class_fiber"> <code class="computeroutput">fiber</code></a> subclass to store such
One might suggest deriving a custom <a class="link" href="fiber_mgmt/fiber.html#class_fiber"><code class="computeroutput">fiber</code></a> subclass to store such
properties. There are a couple of reasons for the present mechanism.
</p>
<div class="orderedlist"><ol class="orderedlist" type="1">
<li class="listitem">
<span class="bold"><strong>Boost.Fiber</strong></span> provides a number of different
ways to launch a fiber. (Consider <a class="link" href="synchronization/futures/future.html#fibers_async"> <code class="computeroutput">fibers::async()</code></a>.) Higher-level
ways to launch a fiber. (Consider <a class="link" href="synchronization/futures/future.html#fibers_async"><code class="computeroutput">fibers::async()</code></a>.) Higher-level
libraries might introduce additional such wrapper functions. A custom scheduler
must associate its custom properties with <span class="emphasis"><em>every</em></span> fiber
in the thread, not only the ones explicitly launched by instantiating a
@@ -85,7 +85,7 @@
a fiber on that thread.
</li>
<li class="listitem">
The <a class="link" href="fiber_mgmt/fiber.html#class_fiber"> <code class="computeroutput">fiber</code></a> class is actually just a handle to internal <a class="link" href="scheduling.html#class_context"> <code class="computeroutput">context</code></a> data.
The <a class="link" href="fiber_mgmt/fiber.html#class_fiber"><code class="computeroutput">fiber</code></a> class is actually just a handle to internal <a class="link" href="scheduling.html#class_context"><code class="computeroutput">context</code></a> data.
A subclass of <code class="computeroutput"><span class="identifier">fiber</span></code> would
not add data to <code class="computeroutput"><span class="identifier">context</span></code>.
</li>
@@ -96,8 +96,8 @@
the rest of your application.
</p>
<p>
Instead of deriving a custom scheduler fiber properties subclass from <a class="link" href="fiber_mgmt/fiber.html#class_fiber"> <code class="computeroutput">fiber</code></a>,
you must instead derive it from <a class="link" href="scheduling.html#class_fiber_properties"> <code class="computeroutput">fiber_properties</code></a>.
Instead of deriving a custom scheduler fiber properties subclass from <a class="link" href="fiber_mgmt/fiber.html#class_fiber"><code class="computeroutput">fiber</code></a>,
you must instead derive it from <a class="link" href="scheduling.html#class_fiber_properties"><code class="computeroutput">fiber_properties</code></a>.
</p>
<p>
</p>
@@ -138,7 +138,7 @@
<tr>
<td width="5%" valign="top" align="left"><p><a name="fiber.custom.c1"></a><a href="#fiber.custom.c0"><img src="../../../../../doc/src/images/callouts/1.png" alt="1" border="0"></a> </p></td>
<td valign="top" align="left"><p>
Your subclass constructor must accept a <code class="literal"> <a class="link" href="scheduling.html#class_context"> <code class="computeroutput">context</code></a>*</code>
Your subclass constructor must accept a <code class="literal"><a class="link" href="scheduling.html#class_context"><code class="computeroutput">context</code></a>*</code>
and pass it to the <code class="computeroutput"><span class="identifier">fiber_properties</span></code>
constructor.
</p></td>
@@ -170,7 +170,7 @@
Scheduler Class</a>
</h4>
<p>
Now we can derive a custom scheduler from <a class="link" href="scheduling.html#class_sched_algorithm_with_properties"> <code class="computeroutput">sched_algorithm_with_properties&lt;&gt;</code></a>,
Now we can derive a custom scheduler from <a class="link" href="scheduling.html#class_sched_algorithm_with_properties"><code class="computeroutput">sched_algorithm_with_properties&lt;&gt;</code></a>,
specifying our custom property class <code class="computeroutput"><span class="identifier">priority_props</span></code>
as the template parameter.
</p>
@@ -277,7 +277,7 @@
<tr>
<td width="5%" valign="top" align="left"><p><a name="fiber.custom.c11"></a><a href="#fiber.custom.c10"><img src="../../../../../doc/src/images/callouts/2.png" alt="2" border="0"></a> </p></td>
<td valign="top" align="left"><p>
You must override the <a class="link" href="scheduling.html#sched_algorithm_with_properties_awakened"> <code class="computeroutput">sched_algorithm_with_properties::awakened()</code></a>
You must override the <a class="link" href="scheduling.html#sched_algorithm_with_properties_awakened"><code class="computeroutput">sched_algorithm_with_properties::awakened()</code></a>
method.
This is how your scheduler receives notification of a fiber that has become
ready to run.
@@ -293,7 +293,7 @@
<tr>
<td width="5%" valign="top" align="left"><p><a name="fiber.custom.c15"></a><a href="#fiber.custom.c14"><img src="../../../../../doc/src/images/callouts/4.png" alt="4" border="0"></a> </p></td>
<td valign="top" align="left"><p>
You must override the <a class="link" href="scheduling.html#sched_algorithm_with_properties_pick_next"> <code class="computeroutput">sched_algorithm_with_properties::pick_next()</code></a>
You must override the <a class="link" href="scheduling.html#sched_algorithm_with_properties_pick_next"><code class="computeroutput">sched_algorithm_with_properties::pick_next()</code></a>
method.
This is how your scheduler actually advises the fiber manager of the next
fiber to run.
@@ -302,7 +302,7 @@
<tr>
<td width="5%" valign="top" align="left"><p><a name="fiber.custom.c17"></a><a href="#fiber.custom.c16"><img src="../../../../../doc/src/images/callouts/5.png" alt="5" border="0"></a> </p></td>
<td valign="top" align="left"><p>
You must override <a class="link" href="scheduling.html#sched_algorithm_with_properties_has_ready_fibers"> <code class="computeroutput">sched_algorithm_with_properties::has_ready_fibers()</code></a>
You must override <a class="link" href="scheduling.html#sched_algorithm_with_properties_has_ready_fibers"><code class="computeroutput">sched_algorithm_with_properties::has_ready_fibers()</code></a>
to
inform the fiber manager of the state of your ready queue.
</p></td>
@@ -310,7 +310,7 @@
<tr>
<td width="5%" valign="top" align="left"><p><a name="fiber.custom.c19"></a><a href="#fiber.custom.c18"><img src="../../../../../doc/src/images/callouts/6.png" alt="6" border="0"></a> </p></td>
<td valign="top" align="left"><p>
Overriding <a class="link" href="scheduling.html#sched_algorithm_with_properties_property_change"> <code class="computeroutput">sched_algorithm_with_properties::property_change()</code></a>
Overriding <a class="link" href="scheduling.html#sched_algorithm_with_properties_property_change"><code class="computeroutput">sched_algorithm_with_properties::property_change()</code></a>
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
@@ -328,7 +328,7 @@
</table></div>
<p>
Our example <code class="computeroutput"><span class="identifier">priority_scheduler</span></code>
doesn't override <a class="link" href="scheduling.html#sched_algorithm_with_properties_new_properties"> <code class="computeroutput">sched_algorithm_with_properties::new_properties()</code></a>:
doesn't override <a class="link" href="scheduling.html#sched_algorithm_with_properties_new_properties"><code class="computeroutput">sched_algorithm_with_properties::new_properties()</code></a>:
we're content with allocating <code class="computeroutput"><span class="identifier">priority_props</span></code>
instances on the heap.
</p>
@@ -338,9 +338,9 @@
Default Scheduler</a>
</h4>
<p>
You must call <a class="link" href="fiber_mgmt/fiber.html#use_scheduling_algorithm"> <code class="computeroutput">use_scheduling_algorithm()</code></a> at the start
You must call <a class="link" href="fiber_mgmt/fiber.html#use_scheduling_algorithm"><code class="computeroutput">use_scheduling_algorithm()</code></a> at the start
of each thread on which you want <span class="bold"><strong>Boost.Fiber</strong></span>
to use your custom scheduler rather than its own default <a class="link" href="scheduling.html#class_round_robin"> <code class="computeroutput">round_robin</code></a>.
to use your custom scheduler rather than its own default <a class="link" href="scheduling.html#class_round_robin"><code class="computeroutput">round_robin</code></a>.
Specifically, you must call <code class="computeroutput"><span class="identifier">use_scheduling_algorithm</span><span class="special">()</span></code> before performing any other <span class="bold"><strong>Boost.Fiber</strong></span>
operations on that thread.
</p>
@@ -360,8 +360,8 @@
Properties</a>
</h4>
<p>
The running fiber can access its own <a class="link" href="scheduling.html#class_fiber_properties"> <code class="computeroutput">fiber_properties</code></a> subclass
instance by calling <a class="link" href="fiber_mgmt/this_fiber.html#this_fiber_properties"> <code class="computeroutput">this_fiber::properties()</code></a>. Although
The running fiber can access its own <a class="link" href="scheduling.html#class_fiber_properties"><code class="computeroutput">fiber_properties</code></a> subclass
instance by calling <a class="link" href="fiber_mgmt/this_fiber.html#this_fiber_properties"><code class="computeroutput">this_fiber::properties()</code></a>. Although
<code class="computeroutput"><span class="identifier">properties</span><span class="special">&lt;&gt;()</span></code>
is a nullary function, you must pass, as a template parameter, the <code class="computeroutput"><span class="identifier">fiber_properties</span></code> subclass.
</p>
@@ -372,9 +372,9 @@
<p>
</p>
<p>
Given a <a class="link" href="fiber_mgmt/fiber.html#class_fiber"> <code class="computeroutput">fiber</code></a> instance still connected with a running fiber (that
is, not <a class="link" href="fiber_mgmt/fiber.html#fiber_detach"> <code class="computeroutput">fiber::detach()</code></a>ed), you may access that fiber's properties
using <a class="link" href="fiber_mgmt/fiber.html#fiber_properties"> <code class="computeroutput">fiber::properties()</code></a>. As with <code class="computeroutput"><span class="identifier">this_fiber</span><span class="special">::</span><span class="identifier">properties</span><span class="special">&lt;&gt;()</span></code>, you must pass your <code class="computeroutput"><span class="identifier">fiber_properties</span></code> subclass as the template
Given a <a class="link" href="fiber_mgmt/fiber.html#class_fiber"><code class="computeroutput">fiber</code></a> instance still connected with a running fiber (that
is, not <a class="link" href="fiber_mgmt/fiber.html#fiber_detach"><code class="computeroutput">fiber::detach()</code></a>ed), you may access that fiber's properties
using <a class="link" href="fiber_mgmt/fiber.html#fiber_properties"><code class="computeroutput">fiber::properties()</code></a>. As with <code class="computeroutput"><span class="identifier">this_fiber</span><span class="special">::</span><span class="identifier">properties</span><span class="special">&lt;&gt;()</span></code>, you must pass your <code class="computeroutput"><span class="identifier">fiber_properties</span></code> subclass as the template
parameter.
</p>
<p>
@@ -397,11 +397,11 @@
As shown in the <code class="computeroutput"><span class="identifier">launch</span><span class="special">()</span></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 <a class="link" href="scheduling.html#sched_algorithm_with_properties_pick_next"> <code class="computeroutput">sched_algorithm_with_properties::pick_next()</code></a>.
then make use of this information next time the fiber manager calls <a class="link" href="scheduling.html#sched_algorithm_with_properties_pick_next"><code class="computeroutput">sched_algorithm_with_properties::pick_next()</code></a>.
</p>
<div class="footnotes">
<br><hr width="100" align="left">
<div class="footnote"><p><sup>[<a name="ftn.fiber.custom.f0" href="#fiber.custom.f0" class="para">10</a>] </sup>
<div class="footnote"><p><sup>[<a name="ftn.fiber.custom.f0" href="#fiber.custom.f0" class="para">9</a>] </sup>
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

View File

@@ -66,12 +66,6 @@
<span class="keyword">template</span><span class="special">&lt;</span> <span class="keyword">typename</span> <span class="identifier">PROPS</span> <span class="special">&gt;</span>
<span class="identifier">PROPS</span> <span class="special">&amp;</span> <span class="identifier">properties</span><span class="special">();</span>
<span class="keyword">void</span> <span class="identifier">interruption_point</span><span class="special">();</span>
<span class="keyword">bool</span> <span class="identifier">interruption_requested</span><span class="special">()</span> <span class="keyword">noexcept</span><span class="special">;</span>
<span class="keyword">bool</span> <span class="identifier">interruption_enabled</span><span class="special">()</span> <span class="keyword">noexcept</span><span class="special">;</span>
<span class="keyword">class</span> <span class="identifier">disable_interruption</span><span class="special">;</span>
<span class="keyword">class</span> <span class="identifier">restore_interruption</span><span class="special">;</span>
<span class="special">}}</span>
</pre>
<h4>
@@ -79,8 +73,8 @@
<span><a name="fiber.fiber_mgmt.tutorial"></a></span><a class="link" href="fiber_mgmt.html#fiber.fiber_mgmt.tutorial">Tutorial</a>
</h4>
<p>
Each <a class="link" href="fiber_mgmt/fiber.html#class_fiber"> <code class="computeroutput">fiber</code></a> represents a micro-thread which will be launched and managed
cooperatively by a scheduler. Objects of type <a class="link" href="fiber_mgmt/fiber.html#class_fiber"> <code class="computeroutput">fiber</code></a> are move-only.
Each <a class="link" href="fiber_mgmt/fiber.html#class_fiber"><code class="computeroutput">fiber</code></a> represents a micro-thread which will be launched and managed
cooperatively by a scheduler. Objects of type <a class="link" href="fiber_mgmt/fiber.html#class_fiber"><code class="computeroutput">fiber</code></a> are move-only.
</p>
<pre class="programlisting"><span class="identifier">boost</span><span class="special">::</span><span class="identifier">fibers</span><span class="special">::</span><span class="identifier">fiber</span> <span class="identifier">f1</span><span class="special">;</span> <span class="comment">// not-a-fiber</span>
@@ -117,7 +111,7 @@
<span class="comment">// this leads to undefined behaviour</span>
</pre>
<p>
The spawned <a class="link" href="fiber_mgmt/fiber.html#class_fiber"> <code class="computeroutput">fiber</code></a> does not immediately start running. It is enqueued
The spawned <a class="link" href="fiber_mgmt/fiber.html#class_fiber"><code class="computeroutput">fiber</code></a> 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.
</p>
@@ -126,19 +120,19 @@
<span><a name="fiber.fiber_mgmt.exceptions"></a></span><a class="link" href="fiber_mgmt.html#fiber.fiber_mgmt.exceptions">Exceptions</a>
</h4>
<p>
An exception escaping from the function or callable object passed to the <a class="link" href="fiber_mgmt/fiber.html#class_fiber"> <code class="computeroutput">fiber</code></a>
An exception escaping from the function or callable object passed to the <a class="link" href="fiber_mgmt/fiber.html#class_fiber"><code class="computeroutput">fiber</code></a>
constructor
calls <code class="computeroutput"><span class="identifier">std</span><span class="special">::</span><span class="identifier">terminate</span><span class="special">()</span></code>.
If you need to know which exception was thrown, use <a class="link" href="synchronization/futures/future.html#class_future"> <code class="computeroutput">future&lt;&gt;</code></a> or
<a class="link" href="synchronization/futures/packaged_task.html#class_packaged_task"> <code class="computeroutput">packaged_task&lt;&gt;</code></a>.
If you need to know which exception was thrown, use <a class="link" href="synchronization/futures/future.html#class_future"><code class="computeroutput">future&lt;&gt;</code></a> or
<a class="link" href="synchronization/futures/packaged_task.html#class_packaged_task"><code class="computeroutput">packaged_task&lt;&gt;</code></a>.
</p>
<h4>
<a name="fiber.fiber_mgmt.h4"></a>
<span><a name="fiber.fiber_mgmt.detaching"></a></span><a class="link" href="fiber_mgmt.html#fiber.fiber_mgmt.detaching">Detaching</a>
</h4>
<p>
A <a class="link" href="fiber_mgmt/fiber.html#class_fiber"> <code class="computeroutput">fiber</code></a> can be detached by explicitly invoking the <a class="link" href="fiber_mgmt/fiber.html#fiber_detach"> <code class="computeroutput">fiber::detach()</code></a> member
function. After <a class="link" href="fiber_mgmt/fiber.html#fiber_detach"> <code class="computeroutput">fiber::detach()</code></a> is called on a fiber object, that
A <a class="link" href="fiber_mgmt/fiber.html#class_fiber"><code class="computeroutput">fiber</code></a> can be detached by explicitly invoking the <a class="link" href="fiber_mgmt/fiber.html#fiber_detach"><code class="computeroutput">fiber::detach()</code></a> member
function. After <a class="link" href="fiber_mgmt/fiber.html#fiber_detach"><code class="computeroutput">fiber::detach()</code></a> is called on a fiber object, that
object represents <span class="emphasis"><em>not-a-fiber</em></span>. The fiber object may then
safely be destroyed.
</p>
@@ -147,23 +141,22 @@ constructor
<p>
<span class="bold"><strong>Boost.Fiber</strong></span> provides a number of ways to wait
for a running fiber to complete. You can coordinate even with a detached fiber
using a <a class="link" href="synchronization/mutex_types.html#class_mutex"> <code class="computeroutput">mutex</code></a>, or <a class="link" href="synchronization/conditions.html#class_condition_variable"> <code class="computeroutput">condition_variable</code></a>, or
using a <a class="link" href="synchronization/mutex_types.html#class_mutex"><code class="computeroutput">mutex</code></a>, or <a class="link" href="synchronization/conditions.html#class_condition_variable"><code class="computeroutput">condition_variable</code></a>, or
any of the other <a class="link" href="synchronization.html#synchronization">synchronization objects</a>
provided by the library.
</p>
<p>
If a detached fiber is still running when the thread's main fiber terminates,
that fiber will be <a class="link" href="fiber_mgmt.html#interruption">interrupted</a> and shut
down.<sup>[<a name="fiber.fiber_mgmt.f0" href="#ftn.fiber.fiber_mgmt.f0" class="footnote">1</a>]</sup>
the thread will not shut down.
</p>
<h4>
<a name="fiber.fiber_mgmt.h5"></a>
<span><a name="fiber.fiber_mgmt.joining"></a></span><a class="link" href="fiber_mgmt.html#fiber.fiber_mgmt.joining">Joining</a>
</h4>
<p>
In order to wait for a fiber to finish, the <a class="link" href="fiber_mgmt/fiber.html#fiber_join"> <code class="computeroutput">fiber::join()</code></a> member function
of the <a class="link" href="fiber_mgmt/fiber.html#class_fiber"> <code class="computeroutput">fiber</code></a> object can be used. <a class="link" href="fiber_mgmt/fiber.html#fiber_join"> <code class="computeroutput">fiber::join()</code></a> will block
until the <a class="link" href="fiber_mgmt/fiber.html#class_fiber"> <code class="computeroutput">fiber</code></a> object has completed.
In order to wait for a fiber to finish, the <a class="link" href="fiber_mgmt/fiber.html#fiber_join"><code class="computeroutput">fiber::join()</code></a> member function
of the <a class="link" href="fiber_mgmt/fiber.html#class_fiber"><code class="computeroutput">fiber</code></a> object can be used. <a class="link" href="fiber_mgmt/fiber.html#fiber_join"><code class="computeroutput">fiber::join()</code></a> will block
until the <a class="link" href="fiber_mgmt/fiber.html#class_fiber"><code class="computeroutput">fiber</code></a> object has completed.
</p>
<pre class="programlisting"><span class="keyword">void</span> <span class="identifier">some_fn</span><span class="special">()</span> <span class="special">{</span>
<span class="special">...</span>
@@ -174,18 +167,18 @@ constructor
<span class="identifier">f</span><span class="special">.</span><span class="identifier">join</span><span class="special">();</span>
</pre>
<p>
If the fiber has already completed, then <a class="link" href="fiber_mgmt/fiber.html#fiber_join"> <code class="computeroutput">fiber::join()</code></a> returns immediately
and the joined <a class="link" href="fiber_mgmt/fiber.html#class_fiber"> <code class="computeroutput">fiber</code></a> object becomes <span class="emphasis"><em>not-a-fiber</em></span>.
If the fiber has already completed, then <a class="link" href="fiber_mgmt/fiber.html#fiber_join"><code class="computeroutput">fiber::join()</code></a> returns immediately
and the joined <a class="link" href="fiber_mgmt/fiber.html#class_fiber"><code class="computeroutput">fiber</code></a> object becomes <span class="emphasis"><em>not-a-fiber</em></span>.
</p>
<h4>
<a name="fiber.fiber_mgmt.h6"></a>
<span><a name="fiber.fiber_mgmt.destruction"></a></span><a class="link" href="fiber_mgmt.html#fiber.fiber_mgmt.destruction">Destruction</a>
</h4>
<p>
When a <a class="link" href="fiber_mgmt/fiber.html#class_fiber"> <code class="computeroutput">fiber</code></a> object representing a valid execution context (the fiber
is <a class="link" href="fiber_mgmt/fiber.html#fiber_joinable"> <code class="computeroutput">fiber::joinable()</code></a>) is destroyed, the program terminates. If
you intend the fiber to outlive the <a class="link" href="fiber_mgmt/fiber.html#class_fiber"> <code class="computeroutput">fiber</code></a> object that launched it,
use the <a class="link" href="fiber_mgmt/fiber.html#fiber_detach"> <code class="computeroutput">fiber::detach()</code></a> method.
When a <a class="link" href="fiber_mgmt/fiber.html#class_fiber"><code class="computeroutput">fiber</code></a> object representing a valid execution context (the fiber
is <a class="link" href="fiber_mgmt/fiber.html#fiber_joinable"><code class="computeroutput">fiber::joinable()</code></a>) is destroyed, the program terminates. If
you intend the fiber to outlive the <a class="link" href="fiber_mgmt/fiber.html#class_fiber"><code class="computeroutput">fiber</code></a> object that launched it,
use the <a class="link" href="fiber_mgmt/fiber.html#fiber_detach"><code class="computeroutput">fiber::detach()</code></a> method.
</p>
<pre class="programlisting"><span class="special">{</span>
<span class="identifier">boost</span><span class="special">::</span><span class="identifier">fibers</span><span class="special">::</span><span class="identifier">fiber</span> <span class="identifier">f</span><span class="special">(</span> <span class="identifier">some_fn</span><span class="special">);</span>
@@ -196,157 +189,16 @@ constructor
<span class="identifier">f</span><span class="special">.</span><span class="identifier">detach</span><span class="special">();</span>
<span class="special">}</span> <span class="comment">// okay, program continues</span>
</pre>
<a name="interruption"></a><h4>
<a name="fiber.fiber_mgmt.h7"></a>
<span><a name="fiber.fiber_mgmt.interruption"></a></span><a class="link" href="fiber_mgmt.html#fiber.fiber_mgmt.interruption">Interruption</a>
</h4>
<p>
A valid fiber can be interrupted by invoking its <a class="link" href="fiber_mgmt/fiber.html#fiber_interrupt"> <code class="computeroutput">fiber::interrupt()</code></a> member
function. The next time that fiber executes one of the specific <a class="link" href="fiber_mgmt.html#interruption"><span class="emphasis"><em>interruption-points</em></span></a>
with interruption enabled, a <code class="computeroutput"><span class="identifier">fiber_interrupted</span></code>
exception will be thrown. If this exception is not caught, the fiber will be
terminated, its stack unwound, its stack objects properly destroyed.
</p>
<p>
(<code class="computeroutput"><span class="identifier">fiber_interrupted</span></code>, being thrown
by the library, is similarly caught by the library. It does not cause the program
to terminate.)
</p>
<p>
With <a class="link" href="fiber_mgmt/this_fiber.html#class_disable_interruption"> <code class="computeroutput">disable_interruption</code></a> a fiber can defer being
interrupted.
</p>
<pre class="programlisting"><span class="comment">// interruption enabled at this point</span>
<span class="special">{</span>
<span class="identifier">boost</span><span class="special">::</span><span class="identifier">this_fiber</span><span class="special">::</span><span class="identifier">disable_interruption</span> <span class="identifier">di1</span><span class="special">;</span>
<span class="comment">// interruption disabled</span>
<span class="special">{</span>
<span class="identifier">boost</span><span class="special">::</span><span class="keyword">this</span><span class="special">::</span><span class="identifier">fiber</span><span class="special">::</span><span class="identifier">disable_interruption</span> <span class="identifier">di2</span><span class="special">;</span>
<span class="comment">// interruption still disabled</span>
<span class="special">}</span> <span class="comment">// di2 destroyed; interruption state restored</span>
<span class="comment">// interruption still disabled</span>
<span class="special">}</span> <span class="comment">// di destroyed; interruption state restored</span>
<span class="comment">// interruption enabled</span>
</pre>
<p>
At any point, the interruption state for the current thread can be queried
by calling <a class="link" href="fiber_mgmt/this_fiber.html#this_fiber_interruption_enabled"> <code class="computeroutput">this_fiber::interruption_enabled()</code></a>.
</p>
<p>
(But consider fiber <code class="computeroutput"><span class="identifier">f1</span></code> running
a <a class="link" href="synchronization/futures/packaged_task.html#class_packaged_task"> <code class="computeroutput">packaged_task&lt;&gt;</code></a>. Suppose <code class="computeroutput"><span class="identifier">f1</span></code>
is interrupted. Its associated <a class="link" href="synchronization/futures/future.html#class_future"> <code class="computeroutput">future&lt;&gt;</code></a> will be set with
<code class="computeroutput"><span class="identifier">fiber_interrupted</span></code>. When fiber
<code class="computeroutput"><span class="identifier">f2</span></code> calls <a class="link" href="synchronization/futures/future.html#future_get"> <code class="computeroutput">future::get()</code></a> on
that <code class="computeroutput"><span class="identifier">future</span></code>, <code class="computeroutput"><span class="identifier">get</span><span class="special">()</span></code> will
immediately rethrow <code class="computeroutput"><span class="identifier">fiber_interrupted</span></code>
&#8212; regardless of any <a class="link" href="fiber_mgmt/this_fiber.html#class_disable_interruption"> <code class="computeroutput">disable_interruption</code></a> instance <code class="computeroutput"><span class="identifier">f2</span></code> might have constructed.)
</p>
<p>
The following <a class="link" href="fiber_mgmt.html#interruption"><span class="emphasis"><em>interruption-points</em></span></a>
are defined and will throw <code class="computeroutput"><span class="identifier">fiber_interrupted</span></code>
if <a class="link" href="fiber_mgmt/this_fiber.html#this_fiber_interruption_requested"> <code class="computeroutput">this_fiber::interruption_requested()</code></a> and
<a class="link" href="fiber_mgmt/this_fiber.html#this_fiber_interruption_enabled"> <code class="computeroutput">this_fiber::interruption_enabled()</code></a>.
</p>
<div class="itemizedlist"><ul class="itemizedlist" type="disc">
<li class="listitem">
<a class="link" href="fiber_mgmt/fiber.html#fiber_join"> <code class="computeroutput">fiber::join()</code></a>
</li>
<li class="listitem">
<a class="link" href="synchronization/barriers.html#barrier_wait"> <code class="computeroutput">barrier::wait()</code></a>
</li>
<li class="listitem">
<a class="link" href="synchronization/conditions.html#condition_variable_wait"> <code class="computeroutput">condition_variable::wait()</code></a>
</li>
<li class="listitem">
<a class="link" href="synchronization/conditions.html#condition_variable_wait_for"> <code class="computeroutput">condition_variable::wait_for()</code></a>
</li>
<li class="listitem">
<a class="link" href="synchronization/conditions.html#condition_variable_wait_until"> <code class="computeroutput">condition_variable::wait_until()</code></a>
</li>
<li class="listitem">
<a class="link" href="synchronization/conditions.html#condition_variable_any_wait"> <code class="computeroutput">condition_variable_any::wait()</code></a>
</li>
<li class="listitem">
<a class="link" href="synchronization/conditions.html#condition_variable_any_wait_for"> <code class="computeroutput">condition_variable_any::wait_for()</code></a>
</li>
<li class="listitem">
<a class="link" href="synchronization/conditions.html#condition_variable_any_wait_until"> <code class="computeroutput">condition_variable_any::wait_until()</code></a>
</li>
<li class="listitem">
<a class="link" href="fiber_mgmt/this_fiber.html#this_fiber_sleep_for"> <code class="computeroutput">this_fiber::sleep_for()</code></a>
</li>
<li class="listitem">
<a class="link" href="fiber_mgmt/this_fiber.html#this_fiber_sleep_until"> <code class="computeroutput">this_fiber::sleep_until()</code></a>
</li>
<li class="listitem">
<a class="link" href="fiber_mgmt/this_fiber.html#this_fiber_interruption_point"> <code class="computeroutput">this_fiber::interruption_point()</code></a>
</li>
<li class="listitem">
<a class="link" href="synchronization/channels.html#bounded_channel_push"> <code class="computeroutput">bounded_channel::push()</code></a>
</li>
<li class="listitem">
<a class="link" href="synchronization/channels.html#bounded_channel_push_wait_for"> <code class="computeroutput">bounded_channel::push_wait_for()</code></a>
</li>
<li class="listitem">
<a class="link" href="synchronization/channels.html#bounded_channel_push_wait_until"> <code class="computeroutput">bounded_channel::push_wait_until()</code></a>
</li>
<li class="listitem">
<a class="link" href="synchronization/channels.html#bounded_channel_pop"> <code class="computeroutput">bounded_channel::pop()</code></a>
</li>
<li class="listitem">
<a class="link" href="synchronization/channels.html#bounded_channel_value_pop"> <code class="computeroutput">bounded_channel::value_pop()</code></a>
</li>
<li class="listitem">
<a class="link" href="synchronization/channels.html#bounded_channel_pop_wait_for"> <code class="computeroutput">bounded_channel::pop_wait_for()</code></a>
</li>
<li class="listitem">
<a class="link" href="synchronization/channels.html#bounded_channel_pop_wait_until"> <code class="computeroutput">bounded_channel::pop_wait_until()</code></a>
</li>
<li class="listitem">
<a class="link" href="synchronization/channels.html#unbounded_channel_push"> <code class="computeroutput">unbounded_channel::push()</code></a>
</li>
<li class="listitem">
<a class="link" href="synchronization/channels.html#unbounded_channel_pop"> <code class="computeroutput">unbounded_channel::pop()</code></a>
</li>
<li class="listitem">
<a class="link" href="synchronization/channels.html#unbounded_channel_value_pop"> <code class="computeroutput">unbounded_channel::value_pop()</code></a>
</li>
<li class="listitem">
<a class="link" href="synchronization/channels.html#unbounded_channel_pop_wait_for"> <code class="computeroutput">unbounded_channel::pop_wait_for()</code></a>
</li>
<li class="listitem">
<a class="link" href="synchronization/channels.html#unbounded_channel_pop_wait_until"> <code class="computeroutput">unbounded_channel::pop_wait_until()</code></a>
</li>
<li class="listitem">
<a class="link" href="synchronization/futures/future.html#future_wait"> <code class="computeroutput">future::wait()</code></a>
</li>
<li class="listitem">
<a class="link" href="synchronization/futures/future.html#future_get"> <code class="computeroutput">future::get()</code></a>
</li>
<li class="listitem">
<a class="link" href="synchronization/futures/future.html#future_get_exception_ptr"> <code class="computeroutput">future::get_exception_ptr()</code></a>
</li>
<li class="listitem">
<a class="link" href="synchronization/futures/future.html#shared_future_wait"> <code class="computeroutput">shared_future::wait()</code></a>
</li>
<li class="listitem">
<a class="link" href="synchronization/futures/future.html#shared_future_get"> <code class="computeroutput">shared_future::get()</code></a>
</li>
<li class="listitem">
<a class="link" href="synchronization/futures/future.html#shared_future_get_exception_ptr"> <code class="computeroutput">shared_future::get_exception_ptr()</code></a>
</li>
</ul></div>
<a name="class_fiber_id"></a><h4>
<a name="fiber.fiber_mgmt.h8"></a>
<a name="fiber.fiber_mgmt.h7"></a>
<span><a name="fiber.fiber_mgmt.fiber_ids"></a></span><a class="link" href="fiber_mgmt.html#fiber.fiber_mgmt.fiber_ids">Fiber
IDs</a>
</h4>
<p>
Objects of class <a class="link" href="fiber_mgmt.html#class_fiber_id"><code class="computeroutput"><span class="identifier">fiber</span><span class="special">::</span><span class="identifier">id</span></code></a> can be
used to identify fibers. Each running <a class="link" href="fiber_mgmt/fiber.html#class_fiber"> <code class="computeroutput">fiber</code></a> has a unique <a class="link" href="fiber_mgmt.html#class_fiber_id"><code class="computeroutput"><span class="identifier">fiber</span><span class="special">::</span><span class="identifier">id</span></code></a> obtainable
from the corresponding <a class="link" href="fiber_mgmt/fiber.html#class_fiber"> <code class="computeroutput">fiber</code></a>
by calling the <a class="link" href="fiber_mgmt/fiber.html#fiber_get_id"> <code class="computeroutput">fiber::get_id()</code></a> member
used to identify fibers. Each running <a class="link" href="fiber_mgmt/fiber.html#class_fiber"><code class="computeroutput">fiber</code></a> has a unique <a class="link" href="fiber_mgmt.html#class_fiber_id"><code class="computeroutput"><span class="identifier">fiber</span><span class="special">::</span><span class="identifier">id</span></code></a> obtainable
from the corresponding <a class="link" href="fiber_mgmt/fiber.html#class_fiber"><code class="computeroutput">fiber</code></a>
by calling the <a class="link" href="fiber_mgmt/fiber.html#fiber_get_id"><code class="computeroutput">fiber::get_id()</code></a> member
function. Objects of class <a class="link" href="fiber_mgmt.html#class_fiber_id"><code class="computeroutput"><span class="identifier">fiber</span><span class="special">::</span><span class="identifier">id</span></code></a> 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
@@ -360,16 +212,59 @@ by calling the <a class="link" href="fiber_mgmt/fiber.html#fiber_get_id"> <code
<a class="link" href="fiber_mgmt.html#class_fiber_id"><code class="computeroutput"><span class="identifier">fiber</span><span class="special">::</span><span class="identifier">id</span></code></a> yield a total order for every non-equal
<a class="link" href="fiber_mgmt.html#class_fiber_id"><code class="computeroutput"><span class="identifier">fiber</span><span class="special">::</span><span class="identifier">id</span></code></a>.
</p>
<div class="footnotes">
<br><hr width="100" align="left">
<div class="footnote"><p><sup>[<a name="ftn.fiber.fiber_mgmt.f0" href="#fiber.fiber_mgmt.f0" class="para">1</a>] </sup>
This treatment of detached fibers depends on a detached fiber eventually
either terminating or reaching one of the specified <a class="link" href="fiber_mgmt.html#interruption"><span class="emphasis"><em>interruption-points</em></span></a>.
Note that since <a class="link" href="fiber_mgmt/this_fiber.html#this_fiber_yield"> <code class="computeroutput">this_fiber::yield()</code></a> is <span class="emphasis"><em>not</em></span>
an interruption point, a detached fiber whose only interaction with the Fiber
library is <code class="computeroutput"><span class="identifier">yield</span><span class="special">()</span></code>
cannot cleanly be terminated.
</p></div>
<a name="class_launch_policy"></a><h4>
<a name="fiber.fiber_mgmt.h8"></a>
<span><a name="fiber.fiber_mgmt.enumeration__code__phrase_role__identifier__launch_policy__phrase___code_"></a></span><a class="link" href="fiber_mgmt.html#fiber.fiber_mgmt.enumeration__code__phrase_role__identifier__launch_policy__phrase___code_">Enumeration
<code class="computeroutput"><span class="identifier">launch_policy</span></code></a>
</h4>
<p>
<code class="computeroutput"><span class="identifier">launch_policy</span></code> specifies whether
control passes immediately into a newly-launched fiber.
</p>
<pre class="programlisting"><span class="keyword">enum</span> <span class="keyword">class</span> <span class="identifier">launch_policy</span> <span class="special">{</span>
<span class="identifier">dispatch</span><span class="special">,</span>
<span class="identifier">post</span>
<span class="special">};</span>
</pre>
<h4>
<a name="fiber.fiber_mgmt.h9"></a>
<span><a name="fiber.fiber_mgmt._code__phrase_role__identifier__dispatch__phrase___code_"></a></span><a class="link" href="fiber_mgmt.html#fiber.fiber_mgmt._code__phrase_role__identifier__dispatch__phrase___code_"><code class="computeroutput"><span class="identifier">dispatch</span></code></a>
</h4>
<div class="variablelist">
<p class="title"><b></b></p>
<dl>
<dt><span class="term">Effects:</span></dt>
<dd><p>
A fiber launched with <code class="computeroutput"><span class="identifier">launch_policy</span>
<span class="special">==</span> <span class="identifier">dispatch</span></code>
is entered immediately. In other words, launching a fiber with <code class="computeroutput"><span class="identifier">dispatch</span></code> suspends the caller (the previously-running
fiber) until the fiber scheduler has a chance to resume it later.
</p></dd>
</dl>
</div>
<h4>
<a name="fiber.fiber_mgmt.h10"></a>
<span><a name="fiber.fiber_mgmt._code__phrase_role__identifier__post__phrase___code_"></a></span><a class="link" href="fiber_mgmt.html#fiber.fiber_mgmt._code__phrase_role__identifier__post__phrase___code_"><code class="computeroutput"><span class="identifier">post</span></code></a>
</h4>
<div class="variablelist">
<p class="title"><b></b></p>
<dl>
<dt><span class="term">Effects:</span></dt>
<dd><p>
A fiber launched with <code class="computeroutput"><span class="identifier">launch_policy</span>
<span class="special">==</span> <span class="identifier">post</span></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.
</p></dd>
<dt><span class="term">Note:</span></dt>
<dd><p>
If <code class="computeroutput"><span class="identifier">launch_policy</span></code> is not
explicitly specified, <code class="computeroutput"><span class="identifier">post</span></code>
is the default.
</p></dd>
</dl>
</div>
</div>
<table xmlns:rev="http://www.cs.rpi.edu/~gregod/boost/tools/doc/revision" width="100%"><tr>

View File

@@ -38,9 +38,15 @@
<span class="keyword">template</span><span class="special">&lt;</span> <span class="keyword">typename</span> <span class="identifier">Fn</span><span class="special">,</span> <span class="keyword">typename</span> <span class="special">...</span> <span class="identifier">Args</span> <span class="special">&gt;</span>
<span class="identifier">fiber</span><span class="special">(</span> <span class="identifier">Fn</span> <span class="special">&amp;&amp;,</span> <span class="identifier">Args</span> <span class="special">&amp;&amp;</span> <span class="special">...);</span>
<span class="keyword">template</span><span class="special">&lt;</span> <span class="keyword">typename</span> <span class="identifier">Fn</span><span class="special">,</span> <span class="keyword">typename</span> <span class="special">...</span> <span class="identifier">Args</span> <span class="special">&gt;</span>
<span class="identifier">fiber</span><span class="special">(</span> <a class="link" href="../fiber_mgmt.html#class_launch_policy"><code class="computeroutput"><span class="identifier">launch_policy</span></code></a><span class="special">,</span> <span class="identifier">Fn</span> <span class="special">&amp;&amp;,</span> <span class="identifier">Args</span> <span class="special">&amp;&amp;</span> <span class="special">...);</span>
<span class="keyword">template</span><span class="special">&lt;</span> <span class="keyword">typename</span> <a class="link" href="../stack.html#stack_allocator_concept"><code class="computeroutput"><span class="identifier">StackAllocator</span></code></a><span class="special">,</span> <span class="keyword">typename</span> <span class="identifier">Fn</span><span class="special">,</span> <span class="keyword">typename</span> <span class="special">...</span> <span class="identifier">Args</span> <span class="special">&gt;</span>
<span class="identifier">fiber</span><span class="special">(</span> <a href="http://en.cppreference.com/w/cpp/memory/allocator_arg_t" target="_top"><code class="computeroutput"><span class="identifier">std</span><span class="special">::</span><span class="identifier">allocator_arg_t</span></code></a><span class="special">,</span> <span class="identifier">StackAllocator</span><span class="special">,</span> <span class="identifier">Fn</span> <span class="special">&amp;&amp;,</span> <span class="identifier">Args</span> <span class="special">&amp;&amp;</span> <span class="special">...);</span>
<span class="keyword">template</span><span class="special">&lt;</span> <span class="keyword">typename</span> <a class="link" href="../stack.html#stack_allocator_concept"><code class="computeroutput"><span class="identifier">StackAllocator</span></code></a><span class="special">,</span> <span class="keyword">typename</span> <span class="identifier">Fn</span><span class="special">,</span> <span class="keyword">typename</span> <span class="special">...</span> <span class="identifier">Args</span> <span class="special">&gt;</span>
<span class="identifier">fiber</span><span class="special">(</span> <a class="link" href="../fiber_mgmt.html#class_launch_policy"><code class="computeroutput"><span class="identifier">launch_policy</span></code></a><span class="special">,</span> <a href="http://en.cppreference.com/w/cpp/memory/allocator_arg_t" target="_top"><code class="computeroutput"><span class="identifier">std</span><span class="special">::</span><span class="identifier">allocator_arg_t</span></code></a><span class="special">,</span> <span class="identifier">StackAllocator</span><span class="special">,</span> <span class="identifier">Fn</span> <span class="special">&amp;&amp;,</span> <span class="identifier">Args</span> <span class="special">&amp;&amp;</span> <span class="special">...);</span>
<span class="special">~</span><span class="identifier">fiber</span><span class="special">();</span>
<span class="identifier">fiber</span><span class="special">(</span> <span class="identifier">fiber</span> <span class="keyword">const</span><span class="special">&amp;)</span> <span class="special">=</span> <span class="keyword">delete</span><span class="special">;</span>
@@ -61,8 +67,6 @@
<span class="keyword">void</span> <span class="identifier">join</span><span class="special">();</span>
<span class="keyword">void</span> <span class="identifier">interrupt</span><span class="special">()</span> <span class="keyword">noexcept</span><span class="special">;</span>
<span class="keyword">template</span><span class="special">&lt;</span> <span class="keyword">typename</span> <span class="identifier">PROPS</span> <span class="special">&gt;</span>
<span class="identifier">PROPS</span> <span class="special">&amp;</span> <span class="identifier">properties</span><span class="special">();</span>
<span class="special">};</span>
@@ -88,7 +92,7 @@
<dl>
<dt><span class="term">Effects:</span></dt>
<dd><p>
Constructs a <a class="link" href="fiber.html#class_fiber"> <code class="computeroutput">fiber</code></a> instance that refers to <span class="emphasis"><em>not-a-fiber</em></span>.
Constructs a <a class="link" href="fiber.html#class_fiber"><code class="computeroutput">fiber</code></a> instance that refers to <span class="emphasis"><em>not-a-fiber</em></span>.
</p></dd>
<dt><span class="term">Postconditions:</span></dt>
<dd><p>
@@ -108,8 +112,15 @@
<pre class="programlisting"><span class="keyword">template</span><span class="special">&lt;</span> <span class="keyword">typename</span> <span class="identifier">Fn</span><span class="special">,</span> <span class="keyword">typename</span> <span class="special">...</span> <span class="identifier">Args</span> <span class="special">&gt;</span>
<span class="identifier">fiber</span><span class="special">(</span> <span class="identifier">Fn</span> <span class="special">&amp;&amp;</span> <span class="identifier">fn</span><span class="special">,</span> <span class="identifier">Args</span> <span class="special">&amp;&amp;</span> <span class="special">...</span> <span class="identifier">args</span><span class="special">);</span>
<span class="keyword">template</span><span class="special">&lt;</span> <span class="keyword">typename</span> <span class="identifier">Fn</span><span class="special">,</span> <span class="keyword">typename</span> <span class="special">...</span> <span class="identifier">Args</span> <span class="special">&gt;</span>
<span class="identifier">fiber</span><span class="special">(</span> <a class="link" href="../fiber_mgmt.html#class_launch_policy"><code class="computeroutput"><span class="identifier">launch_policy</span></code></a> <span class="identifier">lpol</span><span class="special">,</span> <span class="identifier">Fn</span> <span class="special">&amp;&amp;</span> <span class="identifier">fn</span><span class="special">,</span> <span class="identifier">Args</span> <span class="special">&amp;&amp;</span> <span class="special">...</span> <span class="identifier">args</span><span class="special">);</span>
<span class="keyword">template</span><span class="special">&lt;</span> <span class="keyword">typename</span> <a class="link" href="../stack.html#stack_allocator_concept"><code class="computeroutput"><span class="identifier">StackAllocator</span></code></a><span class="special">,</span> <span class="keyword">typename</span> <span class="identifier">Fn</span><span class="special">,</span> <span class="keyword">typename</span> <span class="special">...</span> <span class="identifier">Args</span> <span class="special">&gt;</span>
<span class="identifier">fiber</span><span class="special">(</span> <a href="http://en.cppreference.com/w/cpp/memory/allocator_arg_t" target="_top"><code class="computeroutput"><span class="identifier">std</span><span class="special">::</span><span class="identifier">allocator_arg_t</span></code></a><span class="special">,</span> <span class="identifier">StackAllocator</span> <span class="identifier">salloc</span><span class="special">,</span> <span class="identifier">Fn</span> <span class="special">&amp;&amp;</span> <span class="identifier">fn</span><span class="special">,</span> <span class="identifier">Args</span> <span class="special">&amp;&amp;</span> <span class="special">...</span> <span class="identifier">args</span><span class="special">);</span>
<span class="keyword">template</span><span class="special">&lt;</span> <span class="keyword">typename</span> <a class="link" href="../stack.html#stack_allocator_concept"><code class="computeroutput"><span class="identifier">StackAllocator</span></code></a><span class="special">,</span> <span class="keyword">typename</span> <span class="identifier">Fn</span><span class="special">,</span> <span class="keyword">typename</span> <span class="special">...</span> <span class="identifier">Args</span> <span class="special">&gt;</span>
<span class="identifier">fiber</span><span class="special">(</span> <a class="link" href="../fiber_mgmt.html#class_launch_policy"><code class="computeroutput"><span class="identifier">launch_policy</span></code></a> <span class="identifier">lpol</span><span class="special">,</span> <a href="http://en.cppreference.com/w/cpp/memory/allocator_arg_t" target="_top"><code class="computeroutput"><span class="identifier">std</span><span class="special">::</span><span class="identifier">allocator_arg_t</span></code></a><span class="special">,</span> <span class="identifier">StackAllocator</span> <span class="identifier">salloc</span><span class="special">,</span>
<span class="identifier">Fn</span> <span class="special">&amp;&amp;</span> <span class="identifier">fn</span><span class="special">,</span> <span class="identifier">Args</span> <span class="special">&amp;&amp;</span> <span class="special">...</span> <span class="identifier">args</span><span class="special">);</span>
</pre>
<div class="variablelist">
<p class="title"><b></b></p>
@@ -122,7 +133,12 @@
<dt><span class="term">Effects:</span></dt>
<dd><p>
<code class="computeroutput"><span class="identifier">fn</span></code> is copied or moved
into internal storage for access by the new fiber.
into internal storage for access by the new fiber. If <a class="link" href="../fiber_mgmt.html#class_launch_policy"><code class="computeroutput">launch_policy</code></a> is
specified (or defaulted) to <code class="computeroutput"><span class="identifier">post</span></code>,
the new fiber is marked <span class="quote">&#8220;<span class="quote">ready</span>&#8221;</span> and will be entered at
the next opportunity. If <code class="computeroutput"><span class="identifier">launch_policy</span></code>
is specified as <code class="computeroutput"><span class="identifier">dispatch</span></code>,
the calling fiber is suspended and the new fiber is entered immediately.
</p></dd>
<dt><span class="term">Postconditions:</span></dt>
<dd><p>
@@ -140,7 +156,7 @@
is required to allocate a stack for the internal <a href="http://www.boost.org/doc/libs/release/libs/context/doc/html/context/econtext.html" target="_top"><span class="emphasis"><em>execution_context</em></span></a>.
If <code class="computeroutput"><span class="identifier">StackAllocator</span></code> is
not explicitly passed, the default stack allocator depends on <code class="computeroutput"><span class="identifier">BOOST_USE_SEGMENTED_STACKS</span></code>: if defined,
you will get a <a class="link" href="../stack.html#class_segmented_stack"> <code class="computeroutput">segmented_stack</code></a>, else a <a class="link" href="../stack.html#class_fixedsize_stack"> <code class="computeroutput">fixedsize_stack</code></a>.
you will get a <a class="link" href="../stack.html#class_segmented_stack"><code class="computeroutput">segmented_stack</code></a>, else a <a class="link" href="../stack.html#class_fixedsize_stack"><code class="computeroutput">fixedsize_stack</code></a>.
</p></dd>
<dt><span class="term">See also:</span></dt>
<dd><p>
@@ -162,7 +178,7 @@
<dt><span class="term">Effects:</span></dt>
<dd><p>
Transfers ownership of the fiber managed by <code class="computeroutput"><span class="identifier">other</span></code>
to the newly constructed <a class="link" href="fiber.html#class_fiber"> <code class="computeroutput">fiber</code></a> instance.
to the newly constructed <a class="link" href="fiber.html#class_fiber"><code class="computeroutput">fiber</code></a> instance.
</p></dd>
<dt><span class="term">Postconditions:</span></dt>
<dd><p>
@@ -214,15 +230,15 @@
<dl>
<dt><span class="term">Effects:</span></dt>
<dd><p>
If the fiber is <a class="link" href="fiber.html#fiber_joinable"> <code class="computeroutput">fiber::joinable()</code></a>, calls std::terminate.
If the fiber is <a class="link" href="fiber.html#fiber_joinable"><code class="computeroutput">fiber::joinable()</code></a>, calls std::terminate.
Destroys <code class="computeroutput"><span class="special">*</span><span class="keyword">this</span></code>.
</p></dd>
<dt><span class="term">Note:</span></dt>
<dd><p>
The programmer must ensure that the destructor is never executed while
the fiber is still <a class="link" href="fiber.html#fiber_joinable"> <code class="computeroutput">fiber::joinable()</code></a>. Even if you know
that the fiber has completed, you must still call either <a class="link" href="fiber.html#fiber_join"> <code class="computeroutput">fiber::join()</code></a> or
<a class="link" href="fiber.html#fiber_detach"> <code class="computeroutput">fiber::detach()</code></a> before destroying the <code class="computeroutput"><span class="identifier">fiber</span></code>
the fiber is still <a class="link" href="fiber.html#fiber_joinable"><code class="computeroutput">fiber::joinable()</code></a>. Even if you know
that the fiber has completed, you must still call either <a class="link" href="fiber.html#fiber_join"><code class="computeroutput">fiber::join()</code></a> or
<a class="link" href="fiber.html#fiber_detach"><code class="computeroutput">fiber::detach()</code></a> before destroying the <code class="computeroutput"><span class="identifier">fiber</span></code>
object.
</p></dd>
</dl>
@@ -269,7 +285,7 @@
<dl>
<dt><span class="term">Preconditions:</span></dt>
<dd><p>
the fiber is <a class="link" href="fiber.html#fiber_joinable"> <code class="computeroutput">fiber::joinable()</code></a>.
the fiber is <a class="link" href="fiber.html#fiber_joinable"><code class="computeroutput">fiber::joinable()</code></a>.
</p></dd>
<dt><span class="term">Effects:</span></dt>
<dd><p>
@@ -282,20 +298,14 @@
</p></dd>
<dt><span class="term">Throws:</span></dt>
<dd><p>
<code class="computeroutput"><span class="identifier">fiber_interrupted</span></code> if
the current fiber is interrupted or <code class="computeroutput"><span class="identifier">fiber_error</span></code>
<code class="computeroutput"><span class="identifier">fiber_error</span></code>
</p></dd>
<dt><span class="term">Error Conditions:</span></dt>
<dd><p>
<span class="bold"><strong>resource_deadlock_would_occur</strong></span>: if
<code class="computeroutput"><span class="keyword">this</span><span class="special">-&gt;</span><span class="identifier">get_id</span><span class="special">()</span>
<span class="special">==</span> <span class="identifier">boost</span><span class="special">::</span><span class="identifier">this_fiber</span><span class="special">::</span><span class="identifier">get_id</span><span class="special">()</span></code>. <span class="bold"><strong>invalid_argument</strong></span>:
if the fiber is not <a class="link" href="fiber.html#fiber_joinable"> <code class="computeroutput">fiber::joinable()</code></a>.
</p></dd>
<dt><span class="term">Notes:</span></dt>
<dd><p>
<code class="computeroutput"><span class="identifier">join</span><span class="special">()</span></code>
is one of the predefined <a class="link" href="../fiber_mgmt.html#interruption"><span class="emphasis"><em>interruption-points</em></span></a>.
if the fiber is not <a class="link" href="fiber.html#fiber_joinable"><code class="computeroutput">fiber::joinable()</code></a>.
</p></dd>
</dl>
</div>
@@ -315,12 +325,12 @@
<dl>
<dt><span class="term">Preconditions:</span></dt>
<dd><p>
the fiber is <a class="link" href="fiber.html#fiber_joinable"> <code class="computeroutput">fiber::joinable()</code></a>.
the fiber is <a class="link" href="fiber.html#fiber_joinable"><code class="computeroutput">fiber::joinable()</code></a>.
</p></dd>
<dt><span class="term">Effects:</span></dt>
<dd><p>
The fiber of execution becomes detached, and no longer has an associated
<a class="link" href="fiber.html#class_fiber"> <code class="computeroutput">fiber</code></a> object.
<a class="link" href="fiber.html#class_fiber"><code class="computeroutput">fiber</code></a> object.
</p></dd>
<dt><span class="term">Postconditions:</span></dt>
<dd><p>
@@ -334,7 +344,7 @@
<dt><span class="term">Error Conditions:</span></dt>
<dd><p>
<span class="bold"><strong>invalid_argument</strong></span>: if the fiber is
not <a class="link" href="fiber.html#fiber_joinable"> <code class="computeroutput">fiber::joinable()</code></a>.
not <a class="link" href="fiber.html#fiber_joinable"><code class="computeroutput">fiber::joinable()</code></a>.
</p></dd>
</dl>
</div>
@@ -364,36 +374,7 @@
</p></dd>
<dt><span class="term">See also:</span></dt>
<dd><p>
<a class="link" href="this_fiber.html#this_fiber_get_id"> <code class="computeroutput">this_fiber::get_id()</code></a>
</p></dd>
</dl>
</div>
<p>
</p>
<h5>
<a name="fiber_interrupt_bridgehead"></a>
<span><a name="fiber_interrupt"></a></span>
<a class="link" href="fiber.html#fiber_interrupt">Member function <code class="computeroutput">interrupt</code>()</a>
</h5>
<p>
</p>
<pre class="programlisting"><span class="keyword">void</span> <span class="identifier">interrupt</span><span class="special">()</span> <span class="keyword">noexcept</span><span class="special">;</span>
</pre>
<div class="variablelist">
<p class="title"><b></b></p>
<dl>
<dt><span class="term">Effects:</span></dt>
<dd><p>
If <code class="computeroutput"><span class="special">*</span><span class="keyword">this</span></code>
refers to a fiber of execution, request that the fiber will be interrupted
the next time it enters one of the predefined <a class="link" href="../fiber_mgmt.html#interruption"><span class="emphasis"><em>interruption-points</em></span></a>
with interruption enabled, or if it is currently <a class="link" href="../overview.html#blocking"><span class="emphasis"><em>blocked</em></span></a>
in a call to one of the predefined <a class="link" href="../fiber_mgmt.html#interruption"><span class="emphasis"><em>interruption-points</em></span></a>
with interruption enabled.
</p></dd>
<dt><span class="term">Throws:</span></dt>
<dd><p>
Nothing
<a class="link" href="this_fiber.html#this_fiber_get_id"><code class="computeroutput">this_fiber::get_id()</code></a>
</p></dd>
</dl>
</div>
@@ -416,8 +397,8 @@
<dt><span class="term">Preconditions:</span></dt>
<dd><p>
<code class="computeroutput"><span class="special">*</span><span class="keyword">this</span></code>
refers to a fiber of execution. <a class="link" href="fiber.html#use_scheduling_algorithm"> <code class="computeroutput">use_scheduling_algorithm()</code></a> has
been called from this thread with a subclass of <a class="link" href="../scheduling.html#class_sched_algorithm_with_properties"> <code class="computeroutput">sched_algorithm_with_properties&lt;&gt;</code></a> with
refers to a fiber of execution. <a class="link" href="fiber.html#use_scheduling_algorithm"><code class="computeroutput">use_scheduling_algorithm()</code></a> has
been called from this thread with a subclass of <a class="link" href="../scheduling.html#class_sched_algorithm_with_properties"><code class="computeroutput">sched_algorithm_with_properties&lt;&gt;</code></a> with
the same template argument <code class="computeroutput"><span class="identifier">PROPS</span></code>.
</p></dd>
<dt><span class="term">Returns:</span></dt>
@@ -431,7 +412,7 @@
</p></dd>
<dt><span class="term">Note:</span></dt>
<dd><p>
<a class="link" href="../scheduling.html#class_sched_algorithm_with_properties"> <code class="computeroutput">sched_algorithm_with_properties&lt;&gt;</code></a> provides
<a class="link" href="../scheduling.html#class_sched_algorithm_with_properties"><code class="computeroutput">sched_algorithm_with_properties&lt;&gt;</code></a> 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.
@@ -544,7 +525,7 @@
<dt><span class="term">Effects:</span></dt>
<dd><p>
Directs <span class="bold"><strong>Boost.Fiber</strong></span> to use <code class="computeroutput"><span class="identifier">SchedAlgo</span></code>, which must be a concrete
subclass of <a class="link" href="../scheduling.html#class_sched_algorithm"> <code class="computeroutput">sched_algorithm</code></a>, as the scheduling
subclass of <a class="link" href="../scheduling.html#class_sched_algorithm"><code class="computeroutput">sched_algorithm</code></a>, as the scheduling
algorithm for all fibers in the current thread. Pass any required
<code class="computeroutput"><span class="identifier">SchedAlgo</span></code> constructor
arguments as <code class="computeroutput"><span class="identifier">args</span></code>.
@@ -555,7 +536,7 @@
make that thread call <code class="computeroutput"><span class="identifier">use_scheduling_algorithm</span><span class="special">()</span></code> before any other <span class="bold"><strong>Boost.Fiber</strong></span>
entry point. If no scheduler has been set for the current thread by
the time <span class="bold"><strong>Boost.Fiber</strong></span> needs to use
it, the library will create a default <a class="link" href="../scheduling.html#class_round_robin"> <code class="computeroutput">round_robin</code></a> instance
it, the library will create a default <a class="link" href="../scheduling.html#class_round_robin"><code class="computeroutput">round_robin</code></a> instance
for this thread.
</p></dd>
<dt><span class="term">Throws:</span></dt>

View File

@@ -34,11 +34,6 @@
That is, in many respects the main fiber on each thread can be treated like
an explicitly-launched fiber.
</p>
<p>
However, unlike an explicitly-launched fiber, if <code class="computeroutput"><span class="identifier">fiber_interrupted</span></code>
is thrown (or rethrown) on a thread's main fiber without being caught, the
Fiber library cannot catch it: <code class="computeroutput"><span class="identifier">std</span><span class="special">::</span><span class="identifier">terminate</span><span class="special">()</span></code> will be called.
</p>
<pre class="programlisting"><span class="keyword">namespace</span> <span class="identifier">boost</span> <span class="special">{</span>
<span class="keyword">namespace</span> <span class="identifier">this_fiber</span> <span class="special">{</span>
@@ -51,12 +46,6 @@
<span class="keyword">template</span><span class="special">&lt;</span> <span class="keyword">typename</span> <span class="identifier">PROPS</span> <span class="special">&gt;</span>
<span class="identifier">PROPS</span> <span class="special">&amp;</span> <span class="identifier">properties</span><span class="special">();</span>
<span class="keyword">void</span> <span class="identifier">interruption_point</span><span class="special">();</span>
<span class="keyword">bool</span> <span class="identifier">interruption_requested</span><span class="special">()</span> <span class="keyword">noexcept</span><span class="special">;</span>
<span class="keyword">bool</span> <span class="identifier">interruption_enabled</span><span class="special">()</span> <span class="keyword">noexcept</span><span class="special">;</span>
<span class="keyword">class</span> <span class="identifier">disable_interruption</span><span class="special">;</span>
<span class="keyword">class</span> <span class="identifier">restore_interruption</span><span class="special">;</span>
<span class="special">}}</span>
</pre>
<p>
@@ -111,13 +100,7 @@
</p></dd>
<dt><span class="term">Throws:</span></dt>
<dd><p>
<code class="computeroutput"><span class="identifier">fiber_interrupted</span></code> if
the current fiber is interrupted or timeout-related exceptions.
</p></dd>
<dt><span class="term">Note:</span></dt>
<dd><p>
<code class="computeroutput"><span class="identifier">sleep_until</span><span class="special">()</span></code>
is one of the predefined <a class="link" href="../fiber_mgmt.html#interruption"><span class="emphasis"><em>interruption-points</em></span></a>.
timeout-related exceptions.
</p></dd>
<dt><span class="term">Note:</span></dt>
<dd><p>
@@ -160,13 +143,7 @@
</p></dd>
<dt><span class="term">Throws:</span></dt>
<dd><p>
<code class="computeroutput"><span class="identifier">fiber_interrupted</span></code> if
the current fiber is interrupted or timeout-related exceptions.
</p></dd>
<dt><span class="term">Note:</span></dt>
<dd><p>
<code class="computeroutput"><span class="identifier">sleep_for</span><span class="special">()</span></code>
is one of the predefined <a class="link" href="../fiber_mgmt.html#interruption"><span class="emphasis"><em>interruption-points</em></span></a>.
timeout-related exceptions.
</p></dd>
<dt><span class="term">Note:</span></dt>
<dd><p>
@@ -203,11 +180,8 @@
</p></dd>
<dt><span class="term">Note:</span></dt>
<dd><p>
<code class="computeroutput"><span class="identifier">yield</span><span class="special">()</span></code>
is <span class="emphasis"><em>not</em></span> an interruption point. A fiber that calls
<code class="computeroutput"><span class="identifier">yield</span><span class="special">()</span></code>
is not suspended: it is immediately passed to the scheduler as ready
to run.
A fiber that calls <code class="computeroutput"><span class="identifier">yield</span><span class="special">()</span></code> is not suspended: it is immediately
passed to the scheduler as ready to run.
</p></dd>
</dl>
</div>
@@ -231,8 +205,8 @@
<dl>
<dt><span class="term">Preconditions:</span></dt>
<dd><p>
<a class="link" href="fiber.html#use_scheduling_algorithm"> <code class="computeroutput">use_scheduling_algorithm()</code></a> has been called from
this thread with a subclass of <a class="link" href="../scheduling.html#class_sched_algorithm_with_properties"> <code class="computeroutput">sched_algorithm_with_properties&lt;&gt;</code></a> with
<a class="link" href="fiber.html#use_scheduling_algorithm"><code class="computeroutput">use_scheduling_algorithm()</code></a> has been called from
this thread with a subclass of <a class="link" href="../scheduling.html#class_sched_algorithm_with_properties"><code class="computeroutput">sched_algorithm_with_properties&lt;&gt;</code></a> with
the same template argument <code class="computeroutput"><span class="identifier">PROPS</span></code>.
</p></dd>
<dt><span class="term">Returns:</span></dt>
@@ -247,7 +221,7 @@
</p></dd>
<dt><span class="term">Note:</span></dt>
<dd><p>
<a class="link" href="../scheduling.html#class_sched_algorithm_with_properties"> <code class="computeroutput">sched_algorithm_with_properties&lt;&gt;</code></a> provides
<a class="link" href="../scheduling.html#class_sched_algorithm_with_properties"><code class="computeroutput">sched_algorithm_with_properties&lt;&gt;</code></a> 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.
@@ -263,285 +237,6 @@
</p></dd>
</dl>
</div>
<p>
</p>
<h5>
<a name="this_fiber_interruption_point_bridgehead"></a>
<span><a name="this_fiber_interruption_point"></a></span>
<a class="link" href="this_fiber.html#this_fiber_interruption_point">Non-member
function <code class="computeroutput">this_fiber::interruption_point()</code></a>
</h5>
<p>
</p>
<pre class="programlisting"><span class="preprocessor">#include</span> <span class="special">&lt;</span><span class="identifier">boost</span><span class="special">/</span><span class="identifier">fiber</span><span class="special">/</span><span class="identifier">interruption</span><span class="special">.</span><span class="identifier">hpp</span><span class="special">&gt;</span>
<span class="keyword">void</span> <span class="identifier">interruption_point</span><span class="special">();</span>
</pre>
<div class="variablelist">
<p class="title"><b></b></p>
<dl>
<dt><span class="term">Effects:</span></dt>
<dd><p>
Check to see if the current fiber has been interrupted.
</p></dd>
<dt><span class="term">Throws:</span></dt>
<dd><p>
<code class="computeroutput"><span class="identifier">fiber_interrupted</span></code> if
<a class="link" href="this_fiber.html#this_fiber_interruption_enabled"> <code class="computeroutput">this_fiber::interruption_enabled()</code></a> and
<a class="link" href="this_fiber.html#this_fiber_interruption_requested"> <code class="computeroutput">this_fiber::interruption_requested()</code></a> both
return <code class="computeroutput"><span class="keyword">true</span></code>.
</p></dd>
</dl>
</div>
<p>
</p>
<h5>
<a name="this_fiber_interruption_requested_bridgehead"></a>
<span><a name="this_fiber_interruption_requested"></a></span>
<a class="link" href="this_fiber.html#this_fiber_interruption_requested">Non-member
function <code class="computeroutput">this_fiber::interruption_requested()</code></a>
</h5>
<p>
</p>
<pre class="programlisting"><span class="preprocessor">#include</span> <span class="special">&lt;</span><span class="identifier">boost</span><span class="special">/</span><span class="identifier">fiber</span><span class="special">/</span><span class="identifier">interruption</span><span class="special">.</span><span class="identifier">hpp</span><span class="special">&gt;</span>
<span class="keyword">bool</span> <span class="identifier">interruption_requested</span><span class="special">()</span> <span class="keyword">noexcept</span><span class="special">;</span>
</pre>
<div class="variablelist">
<p class="title"><b></b></p>
<dl>
<dt><span class="term">Returns:</span></dt>
<dd><p>
<code class="computeroutput"><span class="keyword">true</span></code> if interruption has
been requested for the current fiber, <code class="computeroutput"><span class="keyword">false</span></code>
otherwise.
</p></dd>
<dt><span class="term">Throws:</span></dt>
<dd><p>
Nothing.
</p></dd>
</dl>
</div>
<p>
</p>
<h5>
<a name="this_fiber_interruption_enabled_bridgehead"></a>
<span><a name="this_fiber_interruption_enabled"></a></span>
<a class="link" href="this_fiber.html#this_fiber_interruption_enabled">Non-member
function <code class="computeroutput">this_fiber::interruption_enabled()</code></a>
</h5>
<p>
</p>
<pre class="programlisting"><span class="preprocessor">#include</span> <span class="special">&lt;</span><span class="identifier">boost</span><span class="special">/</span><span class="identifier">fiber</span><span class="special">/</span><span class="identifier">interruption</span><span class="special">.</span><span class="identifier">hpp</span><span class="special">&gt;</span>
<span class="keyword">bool</span> <span class="identifier">interruption_enabled</span><span class="special">()</span> <span class="keyword">noexcept</span><span class="special">;</span>
</pre>
<div class="variablelist">
<p class="title"><b></b></p>
<dl>
<dt><span class="term">Returns:</span></dt>
<dd><p>
<code class="computeroutput"><span class="keyword">true</span></code> if interruption is
enabled for the current fiber, <code class="computeroutput"><span class="keyword">false</span></code>
otherwise.
</p></dd>
<dt><span class="term">Throws:</span></dt>
<dd><p>
Nothing.
</p></dd>
<dt><span class="term">Note:</span></dt>
<dd><p>
Interruption is enabled by default.
</p></dd>
</dl>
</div>
<p>
</p>
<h5>
<a name="class_disable_interruption_bridgehead"></a>
<span><a name="class_disable_interruption"></a></span>
<a class="link" href="this_fiber.html#class_disable_interruption">Class
<code class="computeroutput">disable_interruption</code></a>
</h5>
<p>
</p>
<pre class="programlisting"><span class="preprocessor">#include</span> <span class="special">&lt;</span><span class="identifier">boost</span><span class="special">/</span><span class="identifier">fiber</span><span class="special">/</span><span class="identifier">interruption</span><span class="special">.</span><span class="identifier">hpp</span><span class="special">&gt;</span>
<span class="keyword">class</span> <span class="identifier">disable_interruption</span> <span class="special">{</span>
<span class="keyword">public</span><span class="special">:</span>
<span class="identifier">disable_interruption</span><span class="special">()</span> <span class="keyword">noexcept</span><span class="special">;</span>
<span class="special">~</span><span class="identifier">disable_interruption</span><span class="special">()</span> <span class="keyword">noexcept</span><span class="special">;</span>
<span class="identifier">disable_interruption</span><span class="special">(</span><span class="keyword">const</span> <span class="identifier">disable_interruption</span><span class="special">&amp;)</span> <span class="special">=</span> <span class="keyword">delete</span><span class="special">;</span>
<span class="identifier">disable_interruption</span><span class="special">&amp;</span> <span class="keyword">operator</span><span class="special">=(</span><span class="keyword">const</span> <span class="identifier">disable_interruption</span><span class="special">&amp;)</span> <span class="special">=</span> <span class="keyword">delete</span><span class="special">;</span>
<span class="special">};</span>
</pre>
<h5>
<a name="fiber.fiber_mgmt.this_fiber.h0"></a>
<span><a name="fiber.fiber_mgmt.this_fiber.constructor"></a></span><a class="link" href="this_fiber.html#fiber.fiber_mgmt.this_fiber.constructor">Constructor</a>
</h5>
<pre class="programlisting"><span class="identifier">disable_interruption</span><span class="special">()</span> <span class="keyword">noexcept</span><span class="special">;</span>
</pre>
<div class="variablelist">
<p class="title"><b></b></p>
<dl>
<dt><span class="term">Effects:</span></dt>
<dd><p>
Stores the current state of <a class="link" href="this_fiber.html#this_fiber_interruption_enabled"> <code class="computeroutput">this_fiber::interruption_enabled()</code></a> and
disables interruption for the current fiber.
</p></dd>
<dt><span class="term">Postconditions:</span></dt>
<dd><p>
<a class="link" href="this_fiber.html#this_fiber_interruption_enabled"> <code class="computeroutput">this_fiber::interruption_enabled()</code></a> returns
<code class="computeroutput"><span class="keyword">false</span></code> for the current
fiber.
</p></dd>
<dt><span class="term">Throws:</span></dt>
<dd><p>
Nothing.
</p></dd>
<dt><span class="term">Note:</span></dt>
<dd><p>
Nesting of <code class="computeroutput"><span class="identifier">disable_interruption</span></code>
instances matters. Constructing a <code class="computeroutput"><span class="identifier">disable_interruption</span></code>
while <a class="link" href="this_fiber.html#this_fiber_interruption_enabled"> <code class="computeroutput">this_fiber::interruption_enabled()</code></a> <code class="computeroutput"><span class="special">==</span> <span class="keyword">false</span></code>
has no effect.
</p></dd>
</dl>
</div>
<h5>
<a name="fiber.fiber_mgmt.this_fiber.h1"></a>
<span><a name="fiber.fiber_mgmt.this_fiber.destructor"></a></span><a class="link" href="this_fiber.html#fiber.fiber_mgmt.this_fiber.destructor">Destructor</a>
</h5>
<pre class="programlisting"><span class="special">~</span><span class="identifier">disable_interruption</span><span class="special">()</span> <span class="keyword">noexcept</span><span class="special">;</span>
</pre>
<div class="variablelist">
<p class="title"><b></b></p>
<dl>
<dt><span class="term">Preconditions:</span></dt>
<dd><p>
Must be called from the same fiber on which <code class="computeroutput"><span class="special">*</span><span class="keyword">this</span></code> was constructed.
</p></dd>
<dt><span class="term">Effects:</span></dt>
<dd><p>
Restores the state of <a class="link" href="this_fiber.html#this_fiber_interruption_enabled"> <code class="computeroutput">this_fiber::interruption_enabled()</code></a> for
the current fiber to the state saved at construction of <code class="computeroutput"><span class="special">*</span><span class="keyword">this</span></code>.
</p></dd>
<dt><span class="term">Postconditions:</span></dt>
<dd><p>
<a class="link" href="this_fiber.html#this_fiber_interruption_enabled"> <code class="computeroutput">this_fiber::interruption_enabled()</code></a> for
the current fiber returns the value stored by the constructor of <code class="computeroutput"><span class="special">*</span><span class="keyword">this</span></code>.
</p></dd>
<dt><span class="term">Note:</span></dt>
<dd><p>
Destroying a <code class="computeroutput"><span class="identifier">disable_interruption</span></code>
constructed while <a class="link" href="this_fiber.html#this_fiber_interruption_enabled"> <code class="computeroutput">this_fiber::interruption_enabled()</code></a> <code class="computeroutput"><span class="special">==</span> <span class="keyword">false</span></code>
has no effect.
</p></dd>
</dl>
</div>
<p>
</p>
<h5>
<a name="class_restore_interruption_bridgehead"></a>
<span><a name="class_restore_interruption"></a></span>
<a class="link" href="this_fiber.html#class_restore_interruption">Class
<code class="computeroutput">restore_interruption</code></a>
</h5>
<p>
</p>
<pre class="programlisting"><span class="preprocessor">#include</span> <span class="special">&lt;</span><span class="identifier">boost</span><span class="special">/</span><span class="identifier">fiber</span><span class="special">/</span><span class="identifier">interruption</span><span class="special">.</span><span class="identifier">hpp</span><span class="special">&gt;</span>
<span class="keyword">class</span> <span class="identifier">restore_interruption</span> <span class="special">{</span>
<span class="keyword">public</span><span class="special">:</span>
<span class="keyword">explicit</span> <span class="identifier">restore_interruption</span><span class="special">(</span><span class="identifier">disable_interruption</span><span class="special">&amp;)</span> <span class="keyword">noexcept</span><span class="special">;</span>
<span class="special">~</span><span class="identifier">restore_interruption</span><span class="special">()</span> <span class="keyword">noexcept</span><span class="special">;</span>
<span class="identifier">restore_interruption</span><span class="special">(</span><span class="keyword">const</span> <span class="identifier">restore_interruption</span><span class="special">&amp;)</span> <span class="special">=</span> <span class="keyword">delete</span><span class="special">;</span>
<span class="identifier">restore_interruption</span><span class="special">&amp;</span> <span class="keyword">operator</span><span class="special">=(</span><span class="keyword">const</span> <span class="identifier">restore_interruption</span><span class="special">&amp;)</span> <span class="special">=</span> <span class="keyword">delete</span><span class="special">;</span>
<span class="special">};</span>
</pre>
<h5>
<a name="fiber.fiber_mgmt.this_fiber.h2"></a>
<span><a name="fiber.fiber_mgmt.this_fiber.constructor0"></a></span><a class="link" href="this_fiber.html#fiber.fiber_mgmt.this_fiber.constructor0">Constructor</a>
</h5>
<pre class="programlisting"><span class="keyword">explicit</span> <span class="identifier">restore_interruption</span><span class="special">(</span><span class="identifier">disable_interruption</span><span class="special">&amp;</span> <span class="identifier">disabler</span><span class="special">)</span> <span class="keyword">noexcept</span><span class="special">;</span>
</pre>
<div class="variablelist">
<p class="title"><b></b></p>
<dl>
<dt><span class="term">Preconditions:</span></dt>
<dd><p>
Must be called from the same fiber on which <code class="computeroutput"><span class="identifier">disabler</span></code>
was constructed.
</p></dd>
<dt><span class="term">Effects:</span></dt>
<dd><p>
Restores the current state of <a class="link" href="this_fiber.html#this_fiber_interruption_enabled"> <code class="computeroutput">this_fiber::interruption_enabled()</code></a> for
the current fiber to that saved in <code class="computeroutput"><span class="identifier">disabler</span></code>.
</p></dd>
<dt><span class="term">Postconditions:</span></dt>
<dd><p>
<a class="link" href="this_fiber.html#this_fiber_interruption_enabled"> <code class="computeroutput">this_fiber::interruption_enabled()</code></a> for
the current fiber returns the value stored in the constructor of <code class="computeroutput"><span class="identifier">disabler</span></code>.
</p></dd>
<dt><span class="term">Throws:</span></dt>
<dd><p>
Nothing.
</p></dd>
<dt><span class="term">Note:</span></dt>
<dd><p>
Nesting of <code class="computeroutput"><span class="identifier">restore_interruption</span></code>
instances does not matter: only the <a class="link" href="this_fiber.html#class_disable_interruption"> <code class="computeroutput">disable_interruption</code></a> instance
passed to the constructor matters. Constructing a <code class="computeroutput"><span class="identifier">restore_interruption</span></code>
with a <code class="computeroutput"><span class="identifier">disable_interruption</span></code>
constructed while <a class="link" href="this_fiber.html#this_fiber_interruption_enabled"> <code class="computeroutput">this_fiber::interruption_enabled()</code></a> <code class="computeroutput"><span class="special">==</span> <span class="keyword">false</span></code>
has no effect.
</p></dd>
</dl>
</div>
<h5>
<a name="fiber.fiber_mgmt.this_fiber.h3"></a>
<span><a name="fiber.fiber_mgmt.this_fiber.destructor0"></a></span><a class="link" href="this_fiber.html#fiber.fiber_mgmt.this_fiber.destructor0">Destructor</a>
</h5>
<pre class="programlisting"><span class="special">~</span><span class="identifier">restore_interruption</span><span class="special">()</span> <span class="keyword">noexcept</span><span class="special">;</span>
</pre>
<div class="variablelist">
<p class="title"><b></b></p>
<dl>
<dt><span class="term">Preconditions:</span></dt>
<dd><p>
Must be called from the same fiber on which <code class="computeroutput"><span class="special">*</span><span class="keyword">this</span></code> was constructed.
</p></dd>
<dt><span class="term">Effects:</span></dt>
<dd><p>
Disables interruption for the current fiber.
</p></dd>
<dt><span class="term">Postconditions:</span></dt>
<dd><p>
<a class="link" href="this_fiber.html#this_fiber_interruption_enabled"> <code class="computeroutput">this_fiber::interruption_enabled()</code></a> for
the current fiber returns <code class="computeroutput"><span class="keyword">false</span></code>.
</p></dd>
<dt><span class="term">Note:</span></dt>
<dd><p>
Destroying a <code class="computeroutput"><span class="identifier">restore_interruption</span></code>
constructed with a <a class="link" href="this_fiber.html#class_disable_interruption"> <code class="computeroutput">disable_interruption</code></a> constructed
while <a class="link" href="this_fiber.html#this_fiber_interruption_enabled"> <code class="computeroutput">this_fiber::interruption_enabled()</code></a> <code class="computeroutput"><span class="special">==</span> <span class="keyword">false</span></code>
has no effect.
</p></dd>
</dl>
</div>
<pre class="programlisting"><span class="keyword">void</span> <span class="identifier">foo</span><span class="special">()</span> <span class="special">{</span>
<span class="comment">// interruption is enabled</span>
<span class="special">{</span>
<span class="identifier">boost</span><span class="special">::</span><span class="identifier">this_fiber</span><span class="special">::</span><span class="identifier">disable_interruption</span> <span class="identifier">di</span><span class="special">;</span>
<span class="comment">// interruption is disabled</span>
<span class="special">{</span>
<span class="identifier">boost</span><span class="special">::</span><span class="identifier">this_fiber</span><span class="special">::</span><span class="identifier">restore_interruption</span> <span class="identifier">ri</span><span class="special">(</span> <span class="identifier">di</span><span class="special">);</span>
<span class="comment">// interruption now enabled</span>
<span class="special">}</span> <span class="comment">// ri destroyed, interruption disabled again</span>
<span class="special">}</span> <span class="comment">// di destructed, interruption state restored</span>
<span class="comment">// interruption now enabled</span>
<span class="special">}</span>
</pre>
</div>
<table xmlns:rev="http://www.cs.rpi.edu/~gregod/boost/tools/doc/revision" width="100%"><tr>
<td align="left"></td>

View File

@@ -40,9 +40,9 @@
at fiber exit</a>
</h4>
<p>
When a fiber exits, the objects associated with each <a class="link" href="fls.html#class_fiber_specific_ptr"> <code class="computeroutput">fiber_specific_ptr</code></a> instance
When a fiber exits, the objects associated with each <a class="link" href="fls.html#class_fiber_specific_ptr"><code class="computeroutput">fiber_specific_ptr</code></a> instance
are destroyed. By default, the object pointed to by a pointer <code class="computeroutput"><span class="identifier">p</span></code> is destroyed by invoking <code class="computeroutput"><span class="keyword">delete</span> <span class="identifier">p</span></code>,
but this can be overridden for a specific instance of <a class="link" href="fls.html#class_fiber_specific_ptr"> <code class="computeroutput">fiber_specific_ptr</code></a> by
but this can be overridden for a specific instance of <a class="link" href="fls.html#class_fiber_specific_ptr"><code class="computeroutput">fiber_specific_ptr</code></a> by
providing a cleanup routine <code class="computeroutput"><span class="identifier">func</span></code>
to the constructor. In this case, the object is destroyed by invoking <code class="computeroutput"><span class="identifier">func</span><span class="special">(</span><span class="identifier">p</span><span class="special">)</span></code>. The cleanup functions are called in an unspecified
order.
@@ -100,9 +100,9 @@
</p></dd>
<dt><span class="term">Effects:</span></dt>
<dd><p>
Construct a <a class="link" href="fls.html#class_fiber_specific_ptr"> <code class="computeroutput">fiber_specific_ptr</code></a> object for storing
Construct a <a class="link" href="fls.html#class_fiber_specific_ptr"><code class="computeroutput">fiber_specific_ptr</code></a> object for storing
a pointer to an object of type <code class="computeroutput"><span class="identifier">T</span></code>
specific to each fiber. When <code class="computeroutput"><span class="identifier">reset</span><span class="special">()</span></code> is called, or the fiber exits, <a class="link" href="fls.html#class_fiber_specific_ptr"> <code class="computeroutput">fiber_specific_ptr</code></a> calls
specific to each fiber. When <code class="computeroutput"><span class="identifier">reset</span><span class="special">()</span></code> is called, or the fiber exits, <a class="link" href="fls.html#class_fiber_specific_ptr"><code class="computeroutput">fiber_specific_ptr</code></a> calls
<code class="computeroutput"><span class="identifier">fn</span><span class="special">(</span><span class="keyword">this</span><span class="special">-&gt;</span><span class="identifier">get</span><span class="special">())</span></code>.
If the no-arguments constructor is used, the default <code class="computeroutput"><span class="keyword">delete</span></code>-based
cleanup function will be used to destroy the fiber-local objects.
@@ -125,7 +125,7 @@
<dl>
<dt><span class="term">Requires:</span></dt>
<dd><p>
All the fiber specific instances associated to this <a class="link" href="fls.html#class_fiber_specific_ptr"> <code class="computeroutput">fiber_specific_ptr</code></a>
All the fiber specific instances associated to this <a class="link" href="fls.html#class_fiber_specific_ptr"><code class="computeroutput">fiber_specific_ptr</code></a>
(except
maybe the one associated to this fiber) must be nullptr.
</p></dd>
@@ -140,7 +140,7 @@
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 <a class="link" href="fls.html#class_fiber_specific_ptr"> <code class="computeroutput">fiber_specific_ptr</code></a> should
which is against the goal of fiber specific data. In general, a <a class="link" href="fls.html#class_fiber_specific_ptr"><code class="computeroutput">fiber_specific_ptr</code></a> should
outlive the fibers that use it.
</p></dd>
</dl>
@@ -152,7 +152,7 @@
</tr>
<tr><td align="left" valign="top"><p>
Care needs to be taken to ensure that any fibers still running after an instance
of <a class="link" href="fls.html#class_fiber_specific_ptr"> <code class="computeroutput">fiber_specific_ptr</code></a> has been destroyed do not call
of <a class="link" href="fls.html#class_fiber_specific_ptr"><code class="computeroutput">fiber_specific_ptr</code></a> has been destroyed do not call
any member functions on that instance.
</p></td></tr>
</table></div>
@@ -187,7 +187,7 @@
<th align="left">Note</th>
</tr>
<tr><td align="left" valign="top"><p>
The initial value associated with an instance of <a class="link" href="fls.html#class_fiber_specific_ptr"> <code class="computeroutput">fiber_specific_ptr</code></a> is
The initial value associated with an instance of <a class="link" href="fls.html#class_fiber_specific_ptr"><code class="computeroutput">fiber_specific_ptr</code></a> is
<code class="computeroutput"><span class="keyword">nullptr</span></code> for each fiber.
</p></td></tr>
</table></div>

View File

@@ -7,7 +7,7 @@
<link rel="home" href="../index.html" title="Chapter&#160;1.&#160;Fiber">
<link rel="up" href="../index.html" title="Chapter&#160;1.&#160;Fiber">
<link rel="prev" href="when_any/when_all_functionality/when_all__heterogeneous_types.html" title="when_all, heterogeneous types">
<link rel="next" href="performance.html" title="Performance">
<link rel="next" href="integration/overview.html" title="Overview">
</head>
<body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF">
<table cellpadding="2" width="100%"><tr>
@@ -20,111 +20,22 @@
</tr></table>
<hr>
<div class="spirit-nav">
<a accesskey="p" href="when_any/when_all_functionality/when_all__heterogeneous_types.html"><img src="../../../../../doc/src/images/prev.png" alt="Prev"></a><a accesskey="u" href="../index.html"><img src="../../../../../doc/src/images/up.png" alt="Up"></a><a accesskey="h" href="../index.html"><img src="../../../../../doc/src/images/home.png" alt="Home"></a><a accesskey="n" href="performance.html"><img src="../../../../../doc/src/images/next.png" alt="Next"></a>
<a accesskey="p" href="when_any/when_all_functionality/when_all__heterogeneous_types.html"><img src="../../../../../doc/src/images/prev.png" alt="Prev"></a><a accesskey="u" href="../index.html"><img src="../../../../../doc/src/images/up.png" alt="Up"></a><a accesskey="h" href="../index.html"><img src="../../../../../doc/src/images/home.png" alt="Home"></a><a accesskey="n" href="integration/overview.html"><img src="../../../../../doc/src/images/next.png" alt="Next"></a>
</div>
<div class="section">
<div class="titlepage"><div><div><h2 class="title" style="clear: both">
<a name="fiber.integration"></a><a name="integration"></a><a class="link" href="integration.html" title="Sharing a Thread with Another Main Loop">Sharing a
Thread with Another Main Loop</a>
</h2></div></div></div>
<h4>
<a name="fiber.integration.h0"></a>
<span><a name="fiber.integration.overview"></a></span><a class="link" href="integration.html#fiber.integration.overview">Overview</a>
</h4>
<p>
As always with cooperative concurrency, it is important not to let any one
fiber monopolize the processor too long: that could <span class="quote">&#8220;<span class="quote">starve</span>&#8221;</span> other
ready fibers. This section discusses a couple of solutions.
</p>
<h4>
<a name="fiber.integration.h1"></a>
<span><a name="fiber.integration.event_driven_program"></a></span><a class="link" href="integration.html#fiber.integration.event_driven_program">Event-Driven
Program</a>
</h4>
<p>
Consider a classic event-driven program, organized around a main loop that
fetches and dispatches incoming I/O events. You are introducing <span class="bold"><strong>Boost.Fiber</strong></span>
because certain asynchronous I/O sequences are logically sequential, and for
those you want to write and maintain code that looks and acts sequential.
</p>
<p>
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.
</p>
<p>
You must ensure that the application's main loop <span class="emphasis"><em>itself</em></span>
doesn't monopolize the processor: that the fibers it launches will get the
CPU cycles they need.
</p>
<p>
The solution is the same as for any fiber that might claim the CPU for an extended
time: introduce calls to <a class="link" href="fiber_mgmt/this_fiber.html#this_fiber_yield"> <code class="computeroutput">this_fiber::yield()</code></a>. The most straightforward
approach is to call <code class="computeroutput"><span class="identifier">yield</span><span class="special">()</span></code>
on every iteration of your existing main loop. In effect, this unifies the
application's main loop with <span class="bold"><strong>Boost.Fiber</strong></span>'s
internal main loop. <code class="computeroutput"><span class="identifier">yield</span><span class="special">()</span></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 class="computeroutput"><span class="identifier">yield</span><span class="special">()</span></code> and
resumes the application's main loop.
</p>
<h4>
<a name="fiber.integration.h2"></a>
<span><a name="fiber.integration.integrating_with__ulink_url__http___www_boost_org_doc_libs_release_libs_asio_index_html__boost_asio__ulink_"></a></span><a class="link" href="integration.html#fiber.integration.integrating_with__ulink_url__http___www_boost_org_doc_libs_release_libs_asio_index_html__boost_asio__ulink_">Integrating
with <a href="http://www.boost.org/doc/libs/release/libs/asio/index.html" target="_top">Boost.Asio</a></a>
</h4>
<p>
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 class="computeroutput"><span class="identifier">run</span><span class="special">()</span></code> function from which control does not return
until application shutdown.
</p>
<p>
A <a href="http://www.boost.org/doc/libs/release/libs/asio/index.html" target="_top">Boost.Asio</a>
program might call <a href="http://www.boost.org/doc/libs/release/doc/html/boost_asio/reference/io_service/run.html" target="_top"><code class="computeroutput"><span class="identifier">io_service</span><span class="special">::</span><span class="identifier">run</span><span class="special">()</span></code></a>
in this way.
</p>
<p>
The trick here is to arrange to pass control to <a class="link" href="fiber_mgmt/this_fiber.html#this_fiber_yield"> <code class="computeroutput">this_fiber::yield()</code></a> frequently.
You can use an <a href="http://www.boost.org/doc/libs/1_59_0/doc/html/boost_asio/reference/high_resolution_timer.html" target="_top">Asio
timer</a> for this purpose. Instantiate the timer, arranging to call a
handler function when the timer expires:
</p>
<p>
[run_service]
</p>
<p>
The handler function calls <code class="computeroutput"><span class="identifier">yield</span><span class="special">()</span></code>, then resets the timer and arranges to wake
up again on expiration:
</p>
<p>
[timer_handler]
</p>
<p>
Then instead of directly calling <code class="computeroutput"><span class="identifier">io_service</span><span class="special">::</span><span class="identifier">run</span><span class="special">()</span></code>,
your application would call the above <code class="computeroutput"><span class="identifier">run_service</span><span class="special">(</span><span class="identifier">io_service</span><span class="special">&amp;)</span></code> wrapper.
</p>
<p>
Since, in this example, we always pass control to the fiber manager via <code class="computeroutput"><span class="identifier">yield</span><span class="special">()</span></code>,
the calling fiber is never blocked. Therefore there is always at least one
ready fiber. Therefore the fiber manager never sleeps.
</p>
<p>
Using <code class="computeroutput"><span class="identifier">std</span><span class="special">::</span><span class="identifier">chrono</span><span class="special">::</span><span class="identifier">seconds</span><span class="special">(</span><span class="number">0</span><span class="special">)</span></code> for <span class="emphasis"><em>every</em></span>
keepalive timer 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. Resetting
the timer for <code class="computeroutput"><span class="identifier">keepalive_iterval</span></code>
allows tuning the responsiveness of this thread relative to others in the same
way as when <span class="bold"><strong>Boost.Fiber</strong></span> is running without
<a href="http://www.boost.org/doc/libs/release/libs/asio/index.html" target="_top">Boost.Asio</a>.
</p>
<p>
The source code above is found in <a href="../../../examples/asio/round_robin.hpp" target="_top">round_robin.hpp</a>.
</p>
<div class="toc"><dl>
<dt><span class="section"><a href="integration/overview.html">Overview</a></span></dt>
<dt><span class="section"><a href="integration/event_driven_program.html">Event-Driven
Program</a></span></dt>
<dt><span class="section"><a href="integration/embedded_main_loop.html">Embedded
Main Loop</a></span></dt>
<dt><span class="section"><a href="integration/deeper_dive_into___boost_asio__.html">Deeper
Dive into <a href="http://www.boost.org/doc/libs/release/libs/asio/index.html" target="_top">Boost.Asio</a></a></span></dt>
</dl></div>
</div>
<table xmlns:rev="http://www.cs.rpi.edu/~gregod/boost/tools/doc/revision" width="100%"><tr>
<td align="left"></td>
@@ -136,7 +47,7 @@
</tr></table>
<hr>
<div class="spirit-nav">
<a accesskey="p" href="when_any/when_all_functionality/when_all__heterogeneous_types.html"><img src="../../../../../doc/src/images/prev.png" alt="Prev"></a><a accesskey="u" href="../index.html"><img src="../../../../../doc/src/images/up.png" alt="Up"></a><a accesskey="h" href="../index.html"><img src="../../../../../doc/src/images/home.png" alt="Home"></a><a accesskey="n" href="performance.html"><img src="../../../../../doc/src/images/next.png" alt="Next"></a>
<a accesskey="p" href="when_any/when_all_functionality/when_all__heterogeneous_types.html"><img src="../../../../../doc/src/images/prev.png" alt="Prev"></a><a accesskey="u" href="../index.html"><img src="../../../../../doc/src/images/up.png" alt="Up"></a><a accesskey="h" href="../index.html"><img src="../../../../../doc/src/images/home.png" alt="Home"></a><a accesskey="n" href="integration/overview.html"><img src="../../../../../doc/src/images/next.png" alt="Next"></a>
</div>
</body>
</html>

View File

@@ -0,0 +1,445 @@
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=US-ASCII">
<title>Deeper Dive into Boost.Asio</title>
<link rel="stylesheet" href="../../../../../../doc/src/boostbook.css" type="text/css">
<meta name="generator" content="DocBook XSL Stylesheets V1.75.2">
<link rel="home" href="../../index.html" title="Chapter&#160;1.&#160;Fiber">
<link rel="up" href="../integration.html" title="Sharing a Thread with Another Main Loop">
<link rel="prev" href="embedded_main_loop.html" title="Embedded Main Loop">
<link rel="next" href="../performance.html" title="Performance">
</head>
<body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF">
<table cellpadding="2" width="100%"><tr>
<td valign="top"><img alt="Boost C++ Libraries" width="277" height="86" src="../../../../../../boost.png"></td>
<td align="center"><a href="../../../../../../index.html">Home</a></td>
<td align="center"><a href="../../../../../../libs/libraries.htm">Libraries</a></td>
<td align="center"><a href="http://www.boost.org/users/people.html">People</a></td>
<td align="center"><a href="http://www.boost.org/users/faq.html">FAQ</a></td>
<td align="center"><a href="../../../../../../more/index.htm">More</a></td>
</tr></table>
<hr>
<div class="spirit-nav">
<a accesskey="p" href="embedded_main_loop.html"><img src="../../../../../../doc/src/images/prev.png" alt="Prev"></a><a accesskey="u" href="../integration.html"><img src="../../../../../../doc/src/images/up.png" alt="Up"></a><a accesskey="h" href="../../index.html"><img src="../../../../../../doc/src/images/home.png" alt="Home"></a><a accesskey="n" href="../performance.html"><img src="../../../../../../doc/src/images/next.png" alt="Next"></a>
</div>
<div class="section">
<div class="titlepage"><div><div><h3 class="title">
<a name="fiber.integration.deeper_dive_into___boost_asio__"></a><a class="link" href="deeper_dive_into___boost_asio__.html" title="Deeper Dive into Boost.Asio">Deeper
Dive into <a href="http://www.boost.org/doc/libs/release/libs/asio/index.html" target="_top">Boost.Asio</a></a>
</h3></div></div></div>
<p>
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!
</p>
<p>
This turns out to be surprisingly tricky. We present a possible approach
in <a href="../../../../examples/asio/round_robin.hpp" target="_top"><code class="computeroutput"><span class="identifier">examples</span><span class="special">/</span><span class="identifier">asio</span><span class="special">/</span><span class="identifier">round_robin</span><span class="special">.</span><span class="identifier">hpp</span></code></a>.
</p>
<p>
One consequence of using <a href="http://www.boost.org/doc/libs/release/libs/asio/index.html" target="_top">Boost.Asio</a>
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.
</p>
<p>
So the fiber scheduler must depend on Asio for suspension and resumption.
It requires Asio handler calls to wake it.
</p>
<p>
One dismaying implication is that we cannot support multiple threads calling
<a href="http://www.boost.org/doc/libs/release/doc/html/boost_asio/reference/io_service/run.html" target="_top"><code class="computeroutput"><span class="identifier">io_service</span><span class="special">::</span><span class="identifier">run</span><span class="special">()</span></code></a>
on the same <code class="computeroutput"><span class="identifier">io_service</span></code> instance.
The reason is that Asio provides no way to constrain a particular handler
to be called only on a specified thread. A fiber scheduler instance is locked
to a particular thread: that instance cannot manage any other thread&#8217;s fibers.
Yet if we allow multiple threads to call <code class="computeroutput"><span class="identifier">io_service</span><span class="special">::</span><span class="identifier">run</span><span class="special">()</span></code>
on the same <code class="computeroutput"><span class="identifier">io_service</span></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
&#8212; but that timer&#8217;s handler may well execute on a different thread!
</p>
<p>
Another implication is that since an Asio-aware fiber scheduler (not to mention
<a class="link" href="../callbacks/then_there_s____boost_asio__.html#callbacks_asio"><code class="computeroutput"><span class="identifier">boost</span><span class="special">::</span><span class="identifier">fibers</span><span class="special">::</span><span class="identifier">asio</span><span class="special">::</span><span class="identifier">yield</span></code></a>)
depends on handler calls from the <code class="computeroutput"><span class="identifier">io_service</span></code>,
it is the application&#8217;s responsibility to ensure that <a href="http://www.boost.org/doc/libs/release/doc/html/boost_asio/reference/io_service/stop.html" target="_top"><code class="computeroutput"><span class="identifier">io_service</span><span class="special">::</span><span class="identifier">stop</span><span class="special">()</span></code></a>
is not called until every fiber has terminated.
</p>
<p>
It is easier to reason about the behavior of the presented <code class="computeroutput"><span class="identifier">asio</span><span class="special">::</span><span class="identifier">round_robin</span></code> scheduler if we require that
after initial setup, the thread&#8217;s main fiber is the fiber that calls <code class="computeroutput"><span class="identifier">io_service</span><span class="special">::</span><span class="identifier">run</span><span class="special">()</span></code>,
so let&#8217;s impose that requirement.
</p>
<p>
Naturally, the first thing we must do on each thread using a custom fiber
scheduler is call <a class="link" href="../fiber_mgmt/fiber.html#use_scheduling_algorithm"><code class="computeroutput">use_scheduling_algorithm()</code></a>. However,
since <code class="computeroutput"><span class="identifier">asio</span><span class="special">::</span><span class="identifier">round_robin</span></code> requires an <code class="computeroutput"><span class="identifier">io_service</span></code>
instance, we must first declare that.
</p>
<p>
</p>
<pre class="programlisting"><span class="identifier">boost</span><span class="special">::</span><span class="identifier">asio</span><span class="special">::</span><span class="identifier">io_service</span> <span class="identifier">io_svc</span><span class="special">;</span>
<span class="identifier">boost</span><span class="special">::</span><span class="identifier">fibers</span><span class="special">::</span><span class="identifier">use_scheduling_algorithm</span><span class="special">&lt;</span> <span class="identifier">boost</span><span class="special">::</span><span class="identifier">fibers</span><span class="special">::</span><span class="identifier">asio</span><span class="special">::</span><span class="identifier">round_robin</span> <span class="special">&gt;(</span> <span class="identifier">io_svc</span><span class="special">);</span>
</pre>
<p>
</p>
<p>
<code class="computeroutput"><span class="identifier">use_scheduling_algorithm</span><span class="special">()</span></code> instantiates <code class="computeroutput"><span class="identifier">asio</span><span class="special">::</span><span class="identifier">round_robin</span></code>,
which naturally calls its constructor:
</p>
<p>
</p>
<pre class="programlisting"><span class="identifier">round_robin</span><span class="special">(</span> <span class="identifier">boost</span><span class="special">::</span><span class="identifier">asio</span><span class="special">::</span><span class="identifier">io_service</span> <span class="special">&amp;</span> <span class="identifier">io_svc</span><span class="special">)</span> <span class="special">:</span>
<span class="identifier">io_svc_</span><span class="special">(</span> <span class="identifier">io_svc</span><span class="special">),</span>
<span class="identifier">suspend_timer_</span><span class="special">(</span> <span class="identifier">io_svc_</span><span class="special">)</span> <span class="special">{</span>
<span class="comment">// We use add_service() very deliberately. This will throw</span>
<span class="comment">// service_already_exists if you pass the same io_service instance to</span>
<span class="comment">// more than one round_robin instance.</span>
<span class="identifier">boost</span><span class="special">::</span><span class="identifier">asio</span><span class="special">::</span><span class="identifier">add_service</span><span class="special">(</span> <span class="identifier">io_svc_</span><span class="special">,</span> <span class="keyword">new</span> <span class="identifier">service</span><span class="special">(</span> <span class="identifier">io_svc_</span><span class="special">));</span>
<span class="special">}</span>
</pre>
<p>
</p>
<p>
<code class="computeroutput"><span class="identifier">asio</span><span class="special">::</span><span class="identifier">round_robin</span></code> binds the passed <code class="computeroutput"><span class="identifier">io_service</span></code> reference and initializes a
<a href="http://www.boost.org/doc/libs/release/doc/html/boost_asio/reference/steady_timer.html" target="_top"><code class="computeroutput"><span class="identifier">boost</span><span class="special">::</span><span class="identifier">asio</span><span class="special">::</span><span class="identifier">steady_timer</span></code></a>:
</p>
<p>
</p>
<pre class="programlisting"><span class="identifier">boost</span><span class="special">::</span><span class="identifier">asio</span><span class="special">::</span><span class="identifier">io_service</span> <span class="special">&amp;</span> <span class="identifier">io_svc_</span><span class="special">;</span>
<span class="identifier">boost</span><span class="special">::</span><span class="identifier">asio</span><span class="special">::</span><span class="identifier">steady_timer</span> <span class="identifier">suspend_timer_</span><span class="special">;</span>
</pre>
<p>
</p>
<p>
Then it calls <a href="http://www.boost.org/doc/libs/release/doc/html/boost_asio/reference/add_service.html" target="_top"><code class="computeroutput"><span class="identifier">boost</span><span class="special">::</span><span class="identifier">asio</span><span class="special">::</span><span class="identifier">add_service</span><span class="special">()</span></code></a>
with a nested <code class="computeroutput"><span class="identifier">service</span></code> struct:
</p>
<p>
</p>
<pre class="programlisting"><span class="keyword">struct</span> <span class="identifier">service</span> <span class="special">:</span> <span class="keyword">public</span> <span class="identifier">boost</span><span class="special">::</span><span class="identifier">asio</span><span class="special">::</span><span class="identifier">io_service</span><span class="special">::</span><span class="identifier">service</span> <span class="special">{</span>
<span class="keyword">static</span> <span class="identifier">boost</span><span class="special">::</span><span class="identifier">asio</span><span class="special">::</span><span class="identifier">io_service</span><span class="special">::</span><span class="identifier">id</span> <span class="identifier">id</span><span class="special">;</span>
<span class="identifier">std</span><span class="special">::</span><span class="identifier">unique_ptr</span><span class="special">&lt;</span> <span class="identifier">boost</span><span class="special">::</span><span class="identifier">asio</span><span class="special">::</span><span class="identifier">io_service</span><span class="special">::</span><span class="identifier">work</span> <span class="special">&gt;</span> <span class="identifier">work_</span><span class="special">;</span>
<span class="identifier">service</span><span class="special">(</span> <span class="identifier">boost</span><span class="special">::</span><span class="identifier">asio</span><span class="special">::</span><span class="identifier">io_service</span> <span class="special">&amp;</span> <span class="identifier">io_svc</span><span class="special">)</span> <span class="special">:</span>
<span class="identifier">boost</span><span class="special">::</span><span class="identifier">asio</span><span class="special">::</span><span class="identifier">io_service</span><span class="special">::</span><span class="identifier">service</span><span class="special">(</span> <span class="identifier">io_svc</span><span class="special">),</span>
<span class="identifier">work_</span><span class="special">{</span> <span class="keyword">new</span> <span class="identifier">boost</span><span class="special">::</span><span class="identifier">asio</span><span class="special">::</span><span class="identifier">io_service</span><span class="special">::</span><span class="identifier">work</span><span class="special">(</span> <span class="identifier">io_svc</span><span class="special">)</span> <span class="special">}</span> <span class="special">{</span>
<span class="identifier">io_svc</span><span class="special">.</span><span class="identifier">post</span><span class="special">([&amp;</span><span class="identifier">io_svc</span><span class="special">](){</span>
</pre>
<p>
</p>
<p>
...
</p>
<p>
</p>
<pre class="programlisting"> <span class="special">});</span>
<span class="special">}</span>
<span class="keyword">virtual</span> <span class="special">~</span><span class="identifier">service</span><span class="special">()</span> <span class="special">{}</span>
<span class="identifier">service</span><span class="special">(</span> <span class="identifier">service</span> <span class="keyword">const</span><span class="special">&amp;)</span> <span class="special">=</span> <span class="keyword">delete</span><span class="special">;</span>
<span class="identifier">service</span> <span class="special">&amp;</span> <span class="keyword">operator</span><span class="special">=(</span> <span class="identifier">service</span> <span class="keyword">const</span><span class="special">&amp;)</span> <span class="special">=</span> <span class="keyword">delete</span><span class="special">;</span>
<span class="keyword">void</span> <span class="identifier">shutdown_service</span><span class="special">()</span> <span class="identifier">override</span> <span class="identifier">final</span> <span class="special">{</span>
<span class="identifier">work_</span><span class="special">.</span><span class="identifier">reset</span><span class="special">();</span>
<span class="special">}</span>
<span class="special">};</span>
</pre>
<p>
</p>
<p>
The <code class="computeroutput"><span class="identifier">service</span></code> struct has a
couple of roles.
</p>
<p>
Its foremost role is to manage a <code class="literal">std::unique_ptr&lt;<a href="http://www.boost.org/doc/libs/release/doc/html/boost_asio/reference/io_service__work.html" target="_top"><code class="computeroutput"><span class="identifier">boost</span><span class="special">::</span><span class="identifier">asio</span><span class="special">::</span><span class="identifier">io_service</span><span class="special">::</span><span class="identifier">work</span></code></a>&gt;</code>. We want the
<code class="computeroutput"><span class="identifier">io_service</span></code> instance to continue
its main loop even when there is no pending Asio I/O.
</p>
<p>
But when <a href="http://www.boost.org/doc/libs/release/doc/html/boost_asio/reference/io_service__service/shutdown_service.html" target="_top"><code class="computeroutput"><span class="identifier">boost</span><span class="special">::</span><span class="identifier">asio</span><span class="special">::</span><span class="identifier">io_service</span><span class="special">::</span><span class="identifier">service</span><span class="special">::</span><span class="identifier">shutdown_service</span><span class="special">()</span></code></a>
is called, we discard the <code class="computeroutput"><span class="identifier">io_service</span><span class="special">::</span><span class="identifier">work</span></code>
instance so the <code class="computeroutput"><span class="identifier">io_service</span></code>
can shut down properly.
</p>
<p>
Its other purpose is to <a href="http://www.boost.org/doc/libs/release/doc/html/boost_asio/reference/io_service/post.html" target="_top"><code class="computeroutput"><span class="identifier">post</span><span class="special">()</span></code></a>
a lambda (not yet shown). Let&#8217;s walk further through the example program before
coming back to explain that lambda.
</p>
<p>
The <code class="computeroutput"><span class="identifier">service</span></code> constructor returns
to <code class="computeroutput"><span class="identifier">asio</span><span class="special">::</span><span class="identifier">round_robin</span></code>&#8217;s constructor, which returns
to <code class="computeroutput"><span class="identifier">use_scheduling_algorithm</span><span class="special">()</span></code>, which returns to the application code.
</p>
<p>
Once it has called <code class="computeroutput"><span class="identifier">use_scheduling_algorithm</span><span class="special">()</span></code>, the application may now launch some number
of fibers:
</p>
<p>
</p>
<pre class="programlisting"><span class="comment">// server</span>
<span class="identifier">tcp</span><span class="special">::</span><span class="identifier">acceptor</span> <span class="identifier">a</span><span class="special">(</span> <span class="identifier">io_svc</span><span class="special">,</span> <span class="identifier">tcp</span><span class="special">::</span><span class="identifier">endpoint</span><span class="special">(</span> <span class="identifier">tcp</span><span class="special">::</span><span class="identifier">v4</span><span class="special">(),</span> <span class="number">9999</span><span class="special">)</span> <span class="special">);</span>
<span class="identifier">boost</span><span class="special">::</span><span class="identifier">fibers</span><span class="special">::</span><span class="identifier">fiber</span><span class="special">(</span> <span class="identifier">server</span><span class="special">,</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">ref</span><span class="special">(</span> <span class="identifier">io_svc</span><span class="special">),</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">ref</span><span class="special">(</span> <span class="identifier">a</span><span class="special">)</span> <span class="special">).</span><span class="identifier">detach</span><span class="special">();</span>
<span class="comment">// client</span>
<span class="keyword">const</span> <span class="keyword">unsigned</span> <span class="identifier">iterations</span> <span class="special">=</span> <span class="number">2</span><span class="special">;</span>
<span class="keyword">const</span> <span class="keyword">unsigned</span> <span class="identifier">clients</span> <span class="special">=</span> <span class="number">3</span><span class="special">;</span>
<span class="identifier">boost</span><span class="special">::</span><span class="identifier">fibers</span><span class="special">::</span><span class="identifier">barrier</span> <span class="identifier">b</span><span class="special">(</span> <span class="identifier">clients</span><span class="special">);</span>
<span class="keyword">for</span> <span class="special">(</span> <span class="keyword">unsigned</span> <span class="identifier">i</span> <span class="special">=</span> <span class="number">0</span><span class="special">;</span> <span class="identifier">i</span> <span class="special">&lt;</span> <span class="identifier">clients</span><span class="special">;</span> <span class="special">++</span><span class="identifier">i</span><span class="special">)</span> <span class="special">{</span>
<span class="identifier">boost</span><span class="special">::</span><span class="identifier">fibers</span><span class="special">::</span><span class="identifier">fiber</span><span class="special">(</span>
<span class="identifier">client</span><span class="special">,</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">ref</span><span class="special">(</span> <span class="identifier">io_svc</span><span class="special">),</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">ref</span><span class="special">(</span> <span class="identifier">a</span><span class="special">),</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">ref</span><span class="special">(</span> <span class="identifier">b</span><span class="special">),</span> <span class="identifier">iterations</span><span class="special">).</span><span class="identifier">detach</span><span class="special">();</span>
<span class="special">}</span>
</pre>
<p>
</p>
<p>
Since we don&#8217;t specify a <a class="link" href="../fiber_mgmt.html#class_launch_policy"><code class="computeroutput">launch_policy</code></a>, these fibers are
ready to run, but have not yet been entered.
</p>
<p>
Having set everything up, the application calls <a href="http://www.boost.org/doc/libs/release/doc/html/boost_asio/reference/io_service/run.html" target="_top"><code class="computeroutput"><span class="identifier">io_service</span><span class="special">::</span><span class="identifier">run</span><span class="special">()</span></code></a>:
</p>
<p>
</p>
<pre class="programlisting"><span class="identifier">io_svc</span><span class="special">.</span><span class="identifier">run</span><span class="special">();</span>
</pre>
<p>
</p>
<p>
Now what?
</p>
<p>
Because this <code class="computeroutput"><span class="identifier">io_service</span></code> instance
owns an <code class="computeroutput"><span class="identifier">io_service</span><span class="special">::</span><span class="identifier">work</span></code> instance, <code class="computeroutput"><span class="identifier">run</span><span class="special">()</span></code> does not immediately return. But &#8212; none of
the fibers that will perform actual work has even been entered yet!
</p>
<p>
Without that initial <code class="computeroutput"><span class="identifier">post</span><span class="special">()</span></code> call in <code class="computeroutput"><span class="identifier">service</span></code>&#8217;s
constructor, <span class="emphasis"><em>nothing</em></span> would happen. The application would
hang right here.
</p>
<p>
So, what should the <code class="computeroutput"><span class="identifier">post</span><span class="special">()</span></code> handler execute? Simply <a class="link" href="../fiber_mgmt/this_fiber.html#this_fiber_yield"><code class="computeroutput">this_fiber::yield()</code></a>?
</p>
<p>
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 class="computeroutput"><span class="identifier">this_fiber</span><span class="special">::</span><span class="identifier">yield</span><span class="special">()</span></code> call first. Control would return to the
<code class="computeroutput"><span class="identifier">post</span><span class="special">()</span></code>
handler, which would return to Asio, and... the application would hang.
</p>
<p>
The <code class="computeroutput"><span class="identifier">post</span><span class="special">()</span></code>
handler could <code class="computeroutput"><span class="identifier">post</span><span class="special">()</span></code>
itself again. But as discussed in <a class="link" href="embedded_main_loop.html#embedded_main_loop">the
previous section</a>, once there are actual I/O operations in flight &#8212; once
we reach a state in which no fiber is ready &#8212;
that would cause the thread to
spin.
</p>
<p>
We could, of course, set an Asio timer &#8212; again as <a class="link" href="embedded_main_loop.html#embedded_main_loop">previously
discussed</a>. But in this <span class="quote">&#8220;<span class="quote">deeper dive,</span>&#8221;</span> we&#8217;re trying to
do a little better.
</p>
<p>
The key to doing better is that since we&#8217;re in a fiber, we can run an actual
loop &#8212; not just a chain of callbacks. We can wait for <span class="quote">&#8220;<span class="quote">something to happen</span>&#8221;</span>
by calling <a href="http://www.boost.org/doc/libs/release/doc/html/boost_asio/reference/io_service/run_one.html" target="_top"><code class="computeroutput"><span class="identifier">io_service</span><span class="special">::</span><span class="identifier">run_one</span><span class="special">()</span></code></a>
&#8212; or we can execute already-queued Asio handlers by calling <a href="http://www.boost.org/doc/libs/release/doc/html/boost_asio/reference/io_service/poll.html" target="_top"><code class="computeroutput"><span class="identifier">io_service</span><span class="special">::</span><span class="identifier">poll</span><span class="special">()</span></code></a>.
</p>
<p>
Here&#8217;s the body of the lambda passed to the <code class="computeroutput"><span class="identifier">post</span><span class="special">()</span></code> call.
</p>
<p>
</p>
<pre class="programlisting"><span class="keyword">while</span> <span class="special">(</span> <span class="special">!</span> <span class="identifier">io_svc</span><span class="special">.</span><span class="identifier">stopped</span><span class="special">()</span> <span class="special">)</span> <span class="special">{</span>
<span class="keyword">if</span> <span class="special">(</span> <span class="identifier">boost</span><span class="special">::</span><span class="identifier">fibers</span><span class="special">::</span><span class="identifier">has_ready_fibers</span><span class="special">()</span> <span class="special">)</span> <span class="special">{</span>
<span class="comment">// run all pending handlers in round_robin</span>
<span class="keyword">while</span> <span class="special">(</span> <span class="identifier">io_svc</span><span class="special">.</span><span class="identifier">poll</span><span class="special">()</span> <span class="special">);</span>
<span class="comment">// run pending (ready) fibers</span>
<span class="identifier">this_fiber</span><span class="special">::</span><span class="identifier">yield</span><span class="special">();</span>
<span class="special">}</span> <span class="keyword">else</span> <span class="special">{</span>
<span class="comment">// run one handler inside io_service</span>
<span class="comment">// if no handler available, block this thread</span>
<span class="keyword">if</span> <span class="special">(</span> <span class="special">!</span> <span class="identifier">io_svc</span><span class="special">.</span><span class="identifier">run_one</span><span class="special">()</span> <span class="special">)</span> <span class="special">{</span>
<span class="keyword">break</span><span class="special">;</span>
<span class="special">}</span>
<span class="special">}</span>
<span class="special">}</span>
</pre>
<p>
</p>
<p>
We want this loop to exit once the <code class="computeroutput"><span class="identifier">io_service</span></code>
instance has been <a href="http://www.boost.org/doc/libs/release/doc/html/boost_asio/reference/io_service/stopped.html" target="_top"><code class="computeroutput"><span class="identifier">stopped</span><span class="special">()</span></code></a>.
</p>
<p>
As long as there are ready fibers, we interleave running ready Asio handlers
with running ready fibers.
</p>
<p>
If there are no ready fibers, we wait by calling <code class="computeroutput"><span class="identifier">run_one</span><span class="special">()</span></code>. Once any Asio handler has been called
&#8212; no matter which &#8212; <code class="computeroutput"><span class="identifier">run_one</span><span class="special">()</span></code>
returns. That handler may have transitioned some fiber to ready state, so
we loop back to check again.
</p>
<p>
(We won&#8217;t describe <code class="computeroutput"><span class="identifier">awakened</span><span class="special">()</span></code>, <code class="computeroutput"><span class="identifier">pick_next</span><span class="special">()</span></code> or <code class="computeroutput"><span class="identifier">has_ready_fibers</span><span class="special">()</span></code>, as these are just like <a class="link" href="../scheduling.html#round_robin_awakened"><code class="computeroutput">round_robin::awakened()</code></a>,
<a class="link" href="../scheduling.html#round_robin_pick_next"><code class="computeroutput">round_robin::pick_next()</code></a> and <a class="link" href="../scheduling.html#round_robin_has_ready_fibers"><code class="computeroutput">round_robin::has_ready_fibers()</code></a>.)
</p>
<p>
That leaves <code class="computeroutput"><span class="identifier">suspend_until</span><span class="special">()</span></code> and <code class="computeroutput"><span class="identifier">notify</span><span class="special">()</span></code>.
</p>
<p>
Doubtless you have been asking yourself: why are we calling <code class="computeroutput"><span class="identifier">io_service</span><span class="special">::</span><span class="identifier">run_one</span><span class="special">()</span></code>
in the lambda loop? Why not call it in <code class="computeroutput"><span class="identifier">suspend_until</span><span class="special">()</span></code>, whose very API was designed for just such
a purpose?
</p>
<p>
Under normal circumstances, when the fiber manager finds no ready fibers,
it calls <a class="link" href="../scheduling.html#sched_algorithm_suspend_until"><code class="computeroutput">sched_algorithm::suspend_until()</code></a>. Why
test <code class="computeroutput"><span class="identifier">has_ready_fibers</span><span class="special">()</span></code>
in the lambda loop? Why not leverage the normal mechanism?
</p>
<p>
The answer is: it matters who&#8217;s asking.
</p>
<p>
Consider the lambda loop shown above. The only <span class="bold"><strong>Boost.Fiber</strong></span>
APIs it engages are <code class="computeroutput"><span class="identifier">has_ready_fibers</span><span class="special">()</span></code> and <a class="link" href="../fiber_mgmt/this_fiber.html#this_fiber_yield"><code class="computeroutput">this_fiber::yield()</code></a>.
<code class="computeroutput"><span class="identifier">yield</span><span class="special">()</span></code>
does not <span class="emphasis"><em>block</em></span> the calling fiber: the calling fiber
does not become unready. It is immediately passed back to <a class="link" href="../scheduling.html#sched_algorithm_awakened"><code class="computeroutput">sched_algorithm::awakened()</code></a>,
to be resumed in its turn when all other ready fibers have had a chance to
run. In other words: during a <code class="computeroutput"><span class="identifier">yield</span><span class="special">()</span></code> call, <span class="emphasis"><em>there is always at least
one ready fiber.</em></span>
</p>
<p>
As long as this lambda loop is still running, the fiber manager does not
call <code class="computeroutput"><span class="identifier">suspend_until</span><span class="special">()</span></code>
because it always has a fiber ready to run.
</p>
<p>
However, the lambda loop <span class="emphasis"><em>itself</em></span> can detect the case
when no <span class="emphasis"><em>other</em></span> fibers are ready to run: the running fiber
is not <span class="emphasis"><em>ready</em></span> but <span class="emphasis"><em>running.</em></span>
</p>
<p>
That said, <code class="computeroutput"><span class="identifier">suspend_until</span><span class="special">()</span></code> and <code class="computeroutput"><span class="identifier">notify</span><span class="special">()</span></code> are in fact called during orderly shutdown
processing, so let&#8217;s try a plausible implementation.
</p>
<p>
</p>
<pre class="programlisting"><span class="keyword">void</span> <span class="identifier">suspend_until</span><span class="special">(</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">chrono</span><span class="special">::</span><span class="identifier">steady_clock</span><span class="special">::</span><span class="identifier">time_point</span> <span class="keyword">const</span><span class="special">&amp;</span> <span class="identifier">abs_time</span><span class="special">)</span> <span class="keyword">noexcept</span> <span class="special">{</span>
<span class="comment">// Set a timer so at least one handler will eventually fire, causing</span>
<span class="comment">// run_one() to eventually return. Set a timer even if abs_time ==</span>
<span class="comment">// time_point::max() so the timer can be canceled by our notify()</span>
<span class="comment">// method -- which calls the handler.</span>
<span class="keyword">if</span> <span class="special">(</span> <span class="identifier">suspend_timer_</span><span class="special">.</span><span class="identifier">expires_at</span><span class="special">()</span> <span class="special">!=</span> <span class="identifier">abs_time</span><span class="special">)</span> <span class="special">{</span>
<span class="comment">// Each expires_at(time_point) call cancels any previous pending</span>
<span class="comment">// call. We could inadvertently spin like this:</span>
<span class="comment">// dispatcher calls suspend_until() with earliest wake time</span>
<span class="comment">// suspend_until() sets suspend_timer_</span>
<span class="comment">// lambda loop calls run_one()</span>
<span class="comment">// some other asio handler runs before timer expires</span>
<span class="comment">// run_one() returns to lambda loop</span>
<span class="comment">// lambda loop yields to dispatcher</span>
<span class="comment">// dispatcher finds no ready fibers</span>
<span class="comment">// dispatcher calls suspend_until() with SAME wake time</span>
<span class="comment">// suspend_until() sets suspend_timer_ to same time, canceling</span>
<span class="comment">// previous async_wait()</span>
<span class="comment">// lambda loop calls run_one()</span>
<span class="comment">// asio calls suspend_timer_ handler with operation_aborted</span>
<span class="comment">// run_one() returns to lambda loop... etc. etc.</span>
<span class="comment">// So only actually set the timer when we're passed a DIFFERENT</span>
<span class="comment">// abs_time value.</span>
<span class="identifier">suspend_timer_</span><span class="special">.</span><span class="identifier">expires_at</span><span class="special">(</span> <span class="identifier">abs_time</span><span class="special">);</span>
<span class="comment">// It really doesn't matter what the suspend_timer_ handler does,</span>
<span class="comment">// or even whether it's called because the timer ran out or was</span>
<span class="comment">// canceled. The whole point is to cause the run_one() call to</span>
<span class="comment">// return. So just pass a no-op lambda with proper signature.</span>
<span class="identifier">suspend_timer_</span><span class="special">.</span><span class="identifier">async_wait</span><span class="special">([](</span><span class="identifier">boost</span><span class="special">::</span><span class="identifier">system</span><span class="special">::</span><span class="identifier">error_code</span> <span class="keyword">const</span><span class="special">&amp;){});</span>
<span class="special">}</span>
<span class="special">}</span>
</pre>
<p>
</p>
<p>
As you might expect, <code class="computeroutput"><span class="identifier">suspend_until</span><span class="special">()</span></code> sets an <a href="http://www.boost.org/doc/libs/release/doc/html/boost_asio/reference/steady_timer.html" target="_top"><code class="computeroutput"><span class="identifier">asio</span><span class="special">::</span><span class="identifier">steady_timer</span></code></a> to <a href="http://www.boost.org/doc/libs/release/doc/html/boost_asio/reference/basic_waitable_timer/expires_at.html" target="_top"><code class="computeroutput"><span class="identifier">expires_at</span><span class="special">()</span></code></a>
the passed <a href="http://en.cppreference.com/w/cpp/chrono/steady_clock" target="_top"><code class="computeroutput"><span class="identifier">std</span><span class="special">::</span><span class="identifier">chrono</span><span class="special">::</span><span class="identifier">steady_clock</span><span class="special">::</span><span class="identifier">time_point</span></code></a>.
Usually.
</p>
<p>
As indicated in comments, we avoid setting <code class="computeroutput"><span class="identifier">suspend_timer_</span></code>
multiple times to the <span class="emphasis"><em>same</em></span> <code class="computeroutput"><span class="identifier">time_point</span></code>
value since every <code class="computeroutput"><span class="identifier">expires_at</span><span class="special">()</span></code> call cancels any previous <a href="http://www.boost.org/doc/libs/release/doc/html/boost_asio/reference/basic_waitable_timer/async_wait.html" target="_top"><code class="computeroutput"><span class="identifier">async_wait</span><span class="special">()</span></code></a>
call. There is a chance that we could spin. Reaching <code class="computeroutput"><span class="identifier">suspend_until</span><span class="special">()</span></code> means the fiber manager intends to yield
the processor to Asio. Cancelling the previous <code class="computeroutput"><span class="identifier">async_wait</span><span class="special">()</span></code> call would fire its handler, causing <code class="computeroutput"><span class="identifier">run_one</span><span class="special">()</span></code>
to return, potentially causing the fiber manager to call <code class="computeroutput"><span class="identifier">suspend_until</span><span class="special">()</span></code> again with the same <code class="computeroutput"><span class="identifier">time_point</span></code>
value...
</p>
<p>
Given that we suspend the thread by calling <code class="computeroutput"><span class="identifier">io_service</span><span class="special">::</span><span class="identifier">run_one</span><span class="special">()</span></code>, what&#8217;s important is that our <code class="computeroutput"><span class="identifier">async_wait</span><span class="special">()</span></code>
call will cause a handler to run, which will cause <code class="computeroutput"><span class="identifier">run_one</span><span class="special">()</span></code> to return. It&#8217;s not so important specifically
what that handler does.
</p>
<p>
</p>
<pre class="programlisting"><span class="keyword">void</span> <span class="identifier">notify</span><span class="special">()</span> <span class="keyword">noexcept</span> <span class="special">{</span>
<span class="comment">// Something has happened that should wake one or more fibers BEFORE</span>
<span class="comment">// suspend_timer_ expires. Reset the timer to cause it to fire</span>
<span class="comment">// immediately, causing the run_one() call to return. In theory we</span>
<span class="comment">// could use cancel() because we don't care whether suspend_timer_'s</span>
<span class="comment">// handler is called with operation_aborted or success. However --</span>
<span class="comment">// cancel() doesn't change the expiration time, and we use</span>
<span class="comment">// suspend_timer_'s expiration time to decide whether it's already</span>
<span class="comment">// set. If suspend_until() set some specific wake time, then notify()</span>
<span class="comment">// canceled it, then suspend_until() was called again with the same</span>
<span class="comment">// wake time, it would match suspend_timer_'s expiration time and we'd</span>
<span class="comment">// refrain from setting the timer. So instead of simply calling</span>
<span class="comment">// cancel(), reset the timer, which cancels the pending sleep AND sets</span>
<span class="comment">// a new expiration time. This will cause us to spin the loop twice --</span>
<span class="comment">// once for the operation_aborted handler, once for timer expiration</span>
<span class="comment">// -- but that shouldn't be a big problem.</span>
<span class="identifier">suspend_timer_</span><span class="special">.</span><span class="identifier">expires_at</span><span class="special">(</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">chrono</span><span class="special">::</span><span class="identifier">steady_clock</span><span class="special">::</span><span class="identifier">now</span><span class="special">()</span> <span class="special">);</span>
<span class="special">}</span>
</pre>
<p>
</p>
<p>
Since an <code class="computeroutput"><span class="identifier">expires_at</span><span class="special">()</span></code>
call cancels any previous <code class="computeroutput"><span class="identifier">async_wait</span><span class="special">()</span></code> call, we can make <code class="computeroutput"><span class="identifier">notify</span><span class="special">()</span></code> simply call <code class="computeroutput"><span class="identifier">steady_timer</span><span class="special">::</span><span class="identifier">expires_at</span><span class="special">()</span></code>. That should cause the <code class="computeroutput"><span class="identifier">io_service</span></code>
to call the <code class="computeroutput"><span class="identifier">async_wait</span><span class="special">()</span></code>
handler with <code class="computeroutput"><span class="identifier">operation_aborted</span></code>.
</p>
<p>
The comments in <code class="computeroutput"><span class="identifier">notify</span><span class="special">()</span></code>
explain why we call <code class="computeroutput"><span class="identifier">expires_at</span><span class="special">()</span></code> rather than <a href="http://www.boost.org/doc/libs/release/doc/html/boost_asio/reference/basic_waitable_timer/cancel.html" target="_top"><code class="computeroutput"><span class="identifier">cancel</span><span class="special">()</span></code></a>.
</p>
<p>
This <code class="computeroutput"><span class="identifier">boost</span><span class="special">::</span><span class="identifier">fibers</span><span class="special">::</span><span class="identifier">asio</span><span class="special">::</span><span class="identifier">round_robin</span></code> implementation is used in
<a href="../../../../examples/asio/autoecho.cpp" target="_top"><code class="computeroutput"><span class="identifier">examples</span><span class="special">/</span><span class="identifier">asio</span><span class="special">/</span><span class="identifier">autoecho</span><span class="special">.</span><span class="identifier">cpp</span></code></a>.
</p>
<p>
It seems possible that you could put together a more elegant Fiber / Asio
integration. But as noted at the outset: it&#8217;s tricky.
</p>
</div>
<table xmlns:rev="http://www.cs.rpi.edu/~gregod/boost/tools/doc/revision" width="100%"><tr>
<td align="left"></td>
<td align="right"><div class="copyright-footer">Copyright &#169; 2013 Oliver Kowalke<p>
Distributed under the Boost Software License, Version 1.0. (See accompanying
file LICENSE_1_0.txt or copy at <a href="http://www.boost.org/LICENSE_1_0.txt" target="_top">http://www.boost.org/LICENSE_1_0.txt</a>)
</p>
</div></td>
</tr></table>
<hr>
<div class="spirit-nav">
<a accesskey="p" href="embedded_main_loop.html"><img src="../../../../../../doc/src/images/prev.png" alt="Prev"></a><a accesskey="u" href="../integration.html"><img src="../../../../../../doc/src/images/up.png" alt="Up"></a><a accesskey="h" href="../../index.html"><img src="../../../../../../doc/src/images/home.png" alt="Home"></a><a accesskey="n" href="../performance.html"><img src="../../../../../../doc/src/images/next.png" alt="Next"></a>
</div>
</body>
</html>

View File

@@ -0,0 +1,77 @@
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=US-ASCII">
<title>Embedded Main Loop</title>
<link rel="stylesheet" href="../../../../../../doc/src/boostbook.css" type="text/css">
<meta name="generator" content="DocBook XSL Stylesheets V1.75.2">
<link rel="home" href="../../index.html" title="Chapter&#160;1.&#160;Fiber">
<link rel="up" href="../integration.html" title="Sharing a Thread with Another Main Loop">
<link rel="prev" href="event_driven_program.html" title="Event-Driven Program">
<link rel="next" href="deeper_dive_into___boost_asio__.html" title="Deeper Dive into Boost.Asio">
</head>
<body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF">
<table cellpadding="2" width="100%"><tr>
<td valign="top"><img alt="Boost C++ Libraries" width="277" height="86" src="../../../../../../boost.png"></td>
<td align="center"><a href="../../../../../../index.html">Home</a></td>
<td align="center"><a href="../../../../../../libs/libraries.htm">Libraries</a></td>
<td align="center"><a href="http://www.boost.org/users/people.html">People</a></td>
<td align="center"><a href="http://www.boost.org/users/faq.html">FAQ</a></td>
<td align="center"><a href="../../../../../../more/index.htm">More</a></td>
</tr></table>
<hr>
<div class="spirit-nav">
<a accesskey="p" href="event_driven_program.html"><img src="../../../../../../doc/src/images/prev.png" alt="Prev"></a><a accesskey="u" href="../integration.html"><img src="../../../../../../doc/src/images/up.png" alt="Up"></a><a accesskey="h" href="../../index.html"><img src="../../../../../../doc/src/images/home.png" alt="Home"></a><a accesskey="n" href="deeper_dive_into___boost_asio__.html"><img src="../../../../../../doc/src/images/next.png" alt="Next"></a>
</div>
<div class="section">
<div class="titlepage"><div><div><h3 class="title">
<a name="fiber.integration.embedded_main_loop"></a><a name="embedded_main_loop"></a><a class="link" href="embedded_main_loop.html" title="Embedded Main Loop">Embedded
Main Loop</a>
</h3></div></div></div>
<p>
More challenging is when the application&#8217;s main loop is embedded in some other
library or framework. Such an application will typically, after performing
all necessary setup, pass control to some form of <code class="computeroutput"><span class="identifier">run</span><span class="special">()</span></code> function from which control does not return
until application shutdown.
</p>
<p>
A <a href="http://www.boost.org/doc/libs/release/libs/asio/index.html" target="_top">Boost.Asio</a>
program might call <a href="http://www.boost.org/doc/libs/release/doc/html/boost_asio/reference/io_service/run.html" target="_top"><code class="computeroutput"><span class="identifier">io_service</span><span class="special">::</span><span class="identifier">run</span><span class="special">()</span></code></a>
in this way.
</p>
<p>
In general, the trick is to arrange to pass control to <a class="link" href="../fiber_mgmt/this_fiber.html#this_fiber_yield"><code class="computeroutput">this_fiber::yield()</code></a> frequently.
You could use an <a href="http://www.boost.org/doc/libs/release/doc/html/boost_asio/reference/high_resolution_timer.html" target="_top">Asio
timer</a> for that purpose. You could instantiate the timer, arranging
to call a handler function when the timer expires. The handler function could
call <code class="computeroutput"><span class="identifier">yield</span><span class="special">()</span></code>,
then reset the timer and arrange to wake up again on its next expiration.
</p>
<p>
Since, in this thought experiment, we always pass control to the fiber manager
via <code class="computeroutput"><span class="identifier">yield</span><span class="special">()</span></code>,
the calling fiber is never blocked. Therefore there is always at least one
ready fiber. Therefore the fiber manager never calls <a class="link" href="../scheduling.html#sched_algorithm_suspend_until"><code class="computeroutput">sched_algorithm::suspend_until()</code></a>.
</p>
<p>
Using <a href="http://www.boost.org/doc/libs/release/doc/html/boost_asio/reference/io_service/post.html" target="_top"><code class="computeroutput"><span class="identifier">io_service</span><span class="special">::</span><span class="identifier">post</span><span class="special">()</span></code></a>
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.
</p>
</div>
<table xmlns:rev="http://www.cs.rpi.edu/~gregod/boost/tools/doc/revision" width="100%"><tr>
<td align="left"></td>
<td align="right"><div class="copyright-footer">Copyright &#169; 2013 Oliver Kowalke<p>
Distributed under the Boost Software License, Version 1.0. (See accompanying
file LICENSE_1_0.txt or copy at <a href="http://www.boost.org/LICENSE_1_0.txt" target="_top">http://www.boost.org/LICENSE_1_0.txt</a>)
</p>
</div></td>
</tr></table>
<hr>
<div class="spirit-nav">
<a accesskey="p" href="event_driven_program.html"><img src="../../../../../../doc/src/images/prev.png" alt="Prev"></a><a accesskey="u" href="../integration.html"><img src="../../../../../../doc/src/images/up.png" alt="Up"></a><a accesskey="h" href="../../index.html"><img src="../../../../../../doc/src/images/home.png" alt="Home"></a><a accesskey="n" href="deeper_dive_into___boost_asio__.html"><img src="../../../../../../doc/src/images/next.png" alt="Next"></a>
</div>
</body>
</html>

View File

@@ -0,0 +1,73 @@
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=US-ASCII">
<title>Event-Driven Program</title>
<link rel="stylesheet" href="../../../../../../doc/src/boostbook.css" type="text/css">
<meta name="generator" content="DocBook XSL Stylesheets V1.75.2">
<link rel="home" href="../../index.html" title="Chapter&#160;1.&#160;Fiber">
<link rel="up" href="../integration.html" title="Sharing a Thread with Another Main Loop">
<link rel="prev" href="overview.html" title="Overview">
<link rel="next" href="embedded_main_loop.html" title="Embedded Main Loop">
</head>
<body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF">
<table cellpadding="2" width="100%"><tr>
<td valign="top"><img alt="Boost C++ Libraries" width="277" height="86" src="../../../../../../boost.png"></td>
<td align="center"><a href="../../../../../../index.html">Home</a></td>
<td align="center"><a href="../../../../../../libs/libraries.htm">Libraries</a></td>
<td align="center"><a href="http://www.boost.org/users/people.html">People</a></td>
<td align="center"><a href="http://www.boost.org/users/faq.html">FAQ</a></td>
<td align="center"><a href="../../../../../../more/index.htm">More</a></td>
</tr></table>
<hr>
<div class="spirit-nav">
<a accesskey="p" href="overview.html"><img src="../../../../../../doc/src/images/prev.png" alt="Prev"></a><a accesskey="u" href="../integration.html"><img src="../../../../../../doc/src/images/up.png" alt="Up"></a><a accesskey="h" href="../../index.html"><img src="../../../../../../doc/src/images/home.png" alt="Home"></a><a accesskey="n" href="embedded_main_loop.html"><img src="../../../../../../doc/src/images/next.png" alt="Next"></a>
</div>
<div class="section">
<div class="titlepage"><div><div><h3 class="title">
<a name="fiber.integration.event_driven_program"></a><a class="link" href="event_driven_program.html" title="Event-Driven Program">Event-Driven
Program</a>
</h3></div></div></div>
<p>
Consider a classic event-driven program, organized around a main loop that
fetches and dispatches incoming I/O events. You are introducing <span class="bold"><strong>Boost.Fiber</strong></span> because certain asynchronous I/O sequences
are logically sequential, and for those you want to write and maintain code
that looks and acts sequential.
</p>
<p>
You are launching fibers on the application&#8217;s main thread because certain
of their actions will affect its user interface, and the application&#8217;s UI
framework permits UI operations only on the main thread. Or perhaps those
fibers need access to main-thread data, and it would be too expensive in
runtime (or development time) to robustly defend every such data item with
thread synchronization primitives.
</p>
<p>
You must ensure that the application&#8217;s main loop <span class="emphasis"><em>itself</em></span>
doesn&#8217;t monopolize the processor: that the fibers it launches will get the
CPU cycles they need.
</p>
<p>
The solution is the same as for any fiber that might claim the CPU for an
extended time: introduce calls to <a class="link" href="../fiber_mgmt/this_fiber.html#this_fiber_yield"><code class="computeroutput">this_fiber::yield()</code></a>. The
most straightforward approach is to call <code class="computeroutput"><span class="identifier">yield</span><span class="special">()</span></code> on every iteration of your existing main
loop. In effect, this unifies the application&#8217;s main loop with <span class="bold"><strong>Boost.Fiber</strong></span>&#8217;s
internal main loop. <code class="computeroutput"><span class="identifier">yield</span><span class="special">()</span></code> allows the fiber manager to run any fibers
that have become ready since the previous iteration of the application&#8217;s main
loop. When these fibers have had a turn, control passes to the thread&#8217;s main
fiber, which returns from <code class="computeroutput"><span class="identifier">yield</span><span class="special">()</span></code> and resumes the application&#8217;s main loop.
</p>
</div>
<table xmlns:rev="http://www.cs.rpi.edu/~gregod/boost/tools/doc/revision" width="100%"><tr>
<td align="left"></td>
<td align="right"><div class="copyright-footer">Copyright &#169; 2013 Oliver Kowalke<p>
Distributed under the Boost Software License, Version 1.0. (See accompanying
file LICENSE_1_0.txt or copy at <a href="http://www.boost.org/LICENSE_1_0.txt" target="_top">http://www.boost.org/LICENSE_1_0.txt</a>)
</p>
</div></td>
</tr></table>
<hr>
<div class="spirit-nav">
<a accesskey="p" href="overview.html"><img src="../../../../../../doc/src/images/prev.png" alt="Prev"></a><a accesskey="u" href="../integration.html"><img src="../../../../../../doc/src/images/up.png" alt="Up"></a><a accesskey="h" href="../../index.html"><img src="../../../../../../doc/src/images/home.png" alt="Home"></a><a accesskey="n" href="embedded_main_loop.html"><img src="../../../../../../doc/src/images/next.png" alt="Next"></a>
</div>
</body>
</html>

View File

@@ -0,0 +1,48 @@
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=US-ASCII">
<title>Overview</title>
<link rel="stylesheet" href="../../../../../../doc/src/boostbook.css" type="text/css">
<meta name="generator" content="DocBook XSL Stylesheets V1.75.2">
<link rel="home" href="../../index.html" title="Chapter&#160;1.&#160;Fiber">
<link rel="up" href="../integration.html" title="Sharing a Thread with Another Main Loop">
<link rel="prev" href="../integration.html" title="Sharing a Thread with Another Main Loop">
<link rel="next" href="event_driven_program.html" title="Event-Driven Program">
</head>
<body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF">
<table cellpadding="2" width="100%"><tr>
<td valign="top"><img alt="Boost C++ Libraries" width="277" height="86" src="../../../../../../boost.png"></td>
<td align="center"><a href="../../../../../../index.html">Home</a></td>
<td align="center"><a href="../../../../../../libs/libraries.htm">Libraries</a></td>
<td align="center"><a href="http://www.boost.org/users/people.html">People</a></td>
<td align="center"><a href="http://www.boost.org/users/faq.html">FAQ</a></td>
<td align="center"><a href="../../../../../../more/index.htm">More</a></td>
</tr></table>
<hr>
<div class="spirit-nav">
<a accesskey="p" href="../integration.html"><img src="../../../../../../doc/src/images/prev.png" alt="Prev"></a><a accesskey="u" href="../integration.html"><img src="../../../../../../doc/src/images/up.png" alt="Up"></a><a accesskey="h" href="../../index.html"><img src="../../../../../../doc/src/images/home.png" alt="Home"></a><a accesskey="n" href="event_driven_program.html"><img src="../../../../../../doc/src/images/next.png" alt="Next"></a>
</div>
<div class="section">
<div class="titlepage"><div><div><h3 class="title">
<a name="fiber.integration.overview"></a><a class="link" href="overview.html" title="Overview">Overview</a>
</h3></div></div></div>
<p>
As always with cooperative concurrency, it is important not to let any one
fiber monopolize the processor too long: that could <span class="quote">&#8220;<span class="quote">starve</span>&#8221;</span>
other ready fibers. This section discusses a couple of solutions.
</p>
</div>
<table xmlns:rev="http://www.cs.rpi.edu/~gregod/boost/tools/doc/revision" width="100%"><tr>
<td align="left"></td>
<td align="right"><div class="copyright-footer">Copyright &#169; 2013 Oliver Kowalke<p>
Distributed under the Boost Software License, Version 1.0. (See accompanying
file LICENSE_1_0.txt or copy at <a href="http://www.boost.org/LICENSE_1_0.txt" target="_top">http://www.boost.org/LICENSE_1_0.txt</a>)
</p>
</div></td>
</tr></table>
<hr>
<div class="spirit-nav">
<a accesskey="p" href="../integration.html"><img src="../../../../../../doc/src/images/prev.png" alt="Prev"></a><a accesskey="u" href="../integration.html"><img src="../../../../../../doc/src/images/up.png" alt="Up"></a><a accesskey="h" href="../../index.html"><img src="../../../../../../doc/src/images/home.png" alt="Home"></a><a accesskey="n" href="event_driven_program.html"><img src="../../../../../../doc/src/images/next.png" alt="Next"></a>
</div>
</body>
</html>

View File

@@ -34,7 +34,7 @@
<p>
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.<sup>[<a name="fiber.migration.f0" href="#ftn.fiber.migration.f0" class="footnote">3</a>]</sup> <sup>,</sup><sup>[<a name="fiber.migration.f1" href="#ftn.fiber.migration.f1" class="footnote">4</a>]</sup>
general, a fiber is not bound to a specific thread.<sup>[<a name="fiber.migration.f0" href="#ftn.fiber.migration.f0" class="footnote">2</a>]</sup><sup>,</sup><sup>[<a name="fiber.migration.f1" href="#ftn.fiber.migration.f1" class="footnote">3</a>]</sup>
</p>
<p>
Migrating a fiber from a logical CPU with heavy workload to another logical
@@ -49,13 +49,13 @@
due to increased latency of memory access.
</p>
<p>
Only fibers that are contained in <a class="link" href="scheduling.html#class_sched_algorithm"> <code class="computeroutput">sched_algorithm</code></a>'s ready
Only fibers that are contained in <a class="link" href="scheduling.html#class_sched_algorithm"><code class="computeroutput">sched_algorithm</code></a>'s ready
queue can migrate between threads. You cannot migrate a running fiber, nor
one that is <a class="link" href="overview.html#blocking"><span class="emphasis"><em>blocked</em></span></a>.
</p>
<p>
In<span class="bold"><strong>Boost.Fiber</strong></span> a fiber is migrated by invoking
<a class="link" href="scheduling.html#context_migrate"> <code class="computeroutput">context::migrate()</code></a> on the <a class="link" href="scheduling.html#class_context"> <code class="computeroutput">context</code></a> instance for a
<a class="link" href="scheduling.html#context_migrate"><code class="computeroutput">context::migrate()</code></a> on the <a class="link" href="scheduling.html#class_context"><code class="computeroutput">context</code></a> instance for a
fiber already associated with the destination thread, passing the <code class="computeroutput"><span class="identifier">context</span></code> for the fiber to be migrated.
</p>
<h4>
@@ -67,7 +67,7 @@
In the example <a href="../../../examples/work_sharing.cpp" target="_top">work_sharing.cpp</a>
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 <a class="link" href="fiber_mgmt/this_fiber.html#this_fiber_yield"> <code class="computeroutput">this_fiber::yield()</code></a>. That puts
each iteration the fiber calls <a class="link" href="fiber_mgmt/this_fiber.html#this_fiber_yield"><code class="computeroutput">this_fiber::yield()</code></a>. That puts
the fiber in the ready queue of the fiber-scheduler <span class="emphasis"><em>shared_ready_queue</em></span>,
running in the current thread. The next fiber ready to be executed is dequeued
from the shared ready queue and resumed by <span class="emphasis"><em>shared_ready_queue</em></span>
@@ -182,7 +182,7 @@
<p>
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 <a class="link" href="synchronization/conditions.html#condition_variable_wait"> <code class="computeroutput">condition_variable::wait()</code></a>,
complete. When the main fiber returns from <a class="link" href="synchronization/conditions.html#condition_variable_wait"><code class="computeroutput">condition_variable::wait()</code></a>,
the thread terminates: the main thread joins all other threads.
</p>
<p>
@@ -311,13 +311,13 @@
The fiber scheduler <code class="computeroutput"><span class="identifier">shared_ready_queue</span></code>
is like <code class="computeroutput"><span class="identifier">round_robin</span></code>, except
that it shares a common ready queue among all participating threads. A thread
participates in this pool by executing <a class="link" href="fiber_mgmt/fiber.html#use_scheduling_algorithm"> <code class="computeroutput">use_scheduling_algorithm()</code></a>
participates in this pool by executing <a class="link" href="fiber_mgmt/fiber.html#use_scheduling_algorithm"><code class="computeroutput">use_scheduling_algorithm()</code></a>
before
any other <span class="bold"><strong>Boost.Fiber</strong></span> operation.
</p>
<p>
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 <a class="link" href="scheduling.html#sched_algorithm_awakened"> <code class="computeroutput">sched_algorithm::awakened()</code></a> (fibers
to all instances of shared_ready_queue. Fibers that are enqueued via <a class="link" href="scheduling.html#sched_algorithm_awakened"><code class="computeroutput">sched_algorithm::awakened()</code></a> (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 <span class="emphasis"><em>not</em></span> be shared between
@@ -356,7 +356,7 @@ before
</tr>
</table></div>
<p>
When <a class="link" href="scheduling.html#sched_algorithm_pick_next"> <code class="computeroutput">sched_algorithm::pick_next()</code></a> gets called inside
When <a class="link" href="scheduling.html#sched_algorithm_pick_next"><code class="computeroutput">sched_algorithm::pick_next()</code></a> gets called inside
one thread, a fiber is dequeued from <span class="emphasis"><em>rqueue_</em></span> and will
be resumed in that thread.
</p>
@@ -409,12 +409,12 @@ before
</p>
<div class="footnotes">
<br><hr width="100" align="left">
<div class="footnote"><p><sup>[<a name="ftn.fiber.migration.f0" href="#fiber.migration.f0" class="para">3</a>] </sup>
<div class="footnote"><p><sup>[<a name="ftn.fiber.migration.f0" href="#fiber.migration.f0" class="para">2</a>] </sup>
The <span class="quote">&#8220;<span class="quote">main</span>&#8221;</span> fiber on each thread, that is, the fiber on which
the thread is launched, cannot migrate to any other thread. Also <span class="bold"><strong>Boost.Fiber</strong></span> implicitly creates a dispatcher fiber
for each thread &#8212; this cannot migrate either.
</p></div>
<div class="footnote"><p><sup>[<a name="ftn.fiber.migration.f1" href="#fiber.migration.f1" class="para">4</a>] </sup>
<div class="footnote"><p><sup>[<a name="ftn.fiber.migration.f1" href="#fiber.migration.f1" class="para">3</a>] </sup>
Of course it would be problematic to migrate a fiber that relies on <a class="link" href="overview.html#thread_local_storage">thread-local storage</a>.
</p></div>
</div>

View File

@@ -6,7 +6,7 @@
<meta name="generator" content="DocBook XSL Stylesheets V1.75.2">
<link rel="home" href="../index.html" title="Chapter&#160;1.&#160;Fiber">
<link rel="up" href="../index.html" title="Chapter&#160;1.&#160;Fiber">
<link rel="prev" href="callbacks.html" title="Integrating Fibers with Asynchronous Callbacks">
<link rel="prev" href="callbacks/then_there_s____boost_asio__.html" title="Then There&#8217;s Boost.Asio">
<link rel="next" href="when_any.html" title="when_any / when_all functionality">
</head>
<body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF">
@@ -20,7 +20,7 @@
</tr></table>
<hr>
<div class="spirit-nav">
<a accesskey="p" href="callbacks.html"><img src="../../../../../doc/src/images/prev.png" alt="Prev"></a><a accesskey="u" href="../index.html"><img src="../../../../../doc/src/images/up.png" alt="Up"></a><a accesskey="h" href="../index.html"><img src="../../../../../doc/src/images/home.png" alt="Home"></a><a accesskey="n" href="when_any.html"><img src="../../../../../doc/src/images/next.png" alt="Next"></a>
<a accesskey="p" href="callbacks/then_there_s____boost_asio__.html"><img src="../../../../../doc/src/images/prev.png" alt="Prev"></a><a accesskey="u" href="../index.html"><img src="../../../../../doc/src/images/up.png" alt="Up"></a><a accesskey="h" href="../index.html"><img src="../../../../../doc/src/images/home.png" alt="Home"></a><a accesskey="n" href="when_any.html"><img src="../../../../../doc/src/images/next.png" alt="Next"></a>
</div>
<div class="section">
<div class="titlepage"><div><div><h2 class="title" style="clear: both">
@@ -60,7 +60,7 @@
<span class="bold"><strong>Boost.Fiber</strong></span> can simplify this problem immensely.
Once you have integrated with the application's main loop as described in
<a class="link" href="integration.html#integration">Sharing a Thread with Another Main Loop</a>,
waiting for the next main-loop iteration is as simple as calling <a class="link" href="fiber_mgmt/this_fiber.html#this_fiber_yield"> <code class="computeroutput">this_fiber::yield()</code></a>.
waiting for the next main-loop iteration is as simple as calling <a class="link" href="fiber_mgmt/this_fiber.html#this_fiber_yield"><code class="computeroutput">this_fiber::yield()</code></a>.
</p>
<h4>
<a name="fiber.nonblocking.h1"></a>
@@ -199,7 +199,7 @@
<p>
</p>
<p>
Once we can transparently wait for the next main-loop iteration using <a class="link" href="fiber_mgmt/this_fiber.html#this_fiber_yield"> <code class="computeroutput">this_fiber::yield()</code></a>,
Once we can transparently wait for the next main-loop iteration using <a class="link" href="fiber_mgmt/this_fiber.html#this_fiber_yield"><code class="computeroutput">this_fiber::yield()</code></a>,
ordinary encapsulation Just Works.
</p>
<p>
@@ -216,7 +216,7 @@
</tr></table>
<hr>
<div class="spirit-nav">
<a accesskey="p" href="callbacks.html"><img src="../../../../../doc/src/images/prev.png" alt="Prev"></a><a accesskey="u" href="../index.html"><img src="../../../../../doc/src/images/up.png" alt="Up"></a><a accesskey="h" href="../index.html"><img src="../../../../../doc/src/images/home.png" alt="Home"></a><a accesskey="n" href="when_any.html"><img src="../../../../../doc/src/images/next.png" alt="Next"></a>
<a accesskey="p" href="callbacks/then_there_s____boost_asio__.html"><img src="../../../../../doc/src/images/prev.png" alt="Prev"></a><a accesskey="u" href="../index.html"><img src="../../../../../doc/src/images/up.png" alt="Up"></a><a accesskey="h" href="../index.html"><img src="../../../../../doc/src/images/home.png" alt="Home"></a><a accesskey="n" href="when_any.html"><img src="../../../../../doc/src/images/next.png" alt="Next"></a>
</div>
</body>
</html>

View File

@@ -120,7 +120,7 @@
<p>
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 <a class="link" href="fls.html#class_fiber_specific_ptr"> <code class="computeroutput">fiber_specific_ptr</code></a>.
storage, please see <a class="link" href="fls.html#class_fiber_specific_ptr"><code class="computeroutput">fiber_specific_ptr</code></a>.
</p>
<a name="cross_thread_sync"></a><h4>
<a name="fiber.overview.h2"></a>
@@ -152,7 +152,7 @@
instance, when a fiber wants to wait for a value from another fiber in the
same thread, using <code class="computeroutput"><span class="identifier">std</span><span class="special">::</span><span class="identifier">future</span></code> would be unfortunate: <code class="computeroutput"><span class="identifier">std</span><span class="special">::</span><span class="identifier">future</span><span class="special">::</span><span class="identifier">get</span><span class="special">()</span></code>
would block the whole thread, preventing the other fiber from delivering its
value. Use <a class="link" href="synchronization/futures/future.html#class_future"> <code class="computeroutput">future&lt;&gt;</code></a> instead.
value. Use <a class="link" href="synchronization/futures/future.html#class_future"><code class="computeroutput">future&lt;&gt;</code></a> instead.
</p>
<p>
Similarly, a fiber that invokes a normal blocking I/O operation will block

View File

@@ -6,7 +6,7 @@
<meta name="generator" content="DocBook XSL Stylesheets V1.75.2">
<link rel="home" href="../index.html" title="Chapter&#160;1.&#160;Fiber">
<link rel="up" href="../index.html" title="Chapter&#160;1.&#160;Fiber">
<link rel="prev" href="integration.html" title="Sharing a Thread with Another Main Loop">
<link rel="prev" href="integration/deeper_dive_into___boost_asio__.html" title="Deeper Dive into Boost.Asio">
<link rel="next" href="custom.html" title="Customization">
</head>
<body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF">
@@ -20,7 +20,7 @@
</tr></table>
<hr>
<div class="spirit-nav">
<a accesskey="p" href="integration.html"><img src="../../../../../doc/src/images/prev.png" alt="Prev"></a><a accesskey="u" href="../index.html"><img src="../../../../../doc/src/images/up.png" alt="Up"></a><a accesskey="h" href="../index.html"><img src="../../../../../doc/src/images/home.png" alt="Home"></a><a accesskey="n" href="custom.html"><img src="../../../../../doc/src/images/next.png" alt="Next"></a>
<a accesskey="p" href="integration/deeper_dive_into___boost_asio__.html"><img src="../../../../../doc/src/images/prev.png" alt="Prev"></a><a accesskey="u" href="../index.html"><img src="../../../../../doc/src/images/up.png" alt="Up"></a><a accesskey="h" href="../index.html"><img src="../../../../../doc/src/images/home.png" alt="Home"></a><a accesskey="n" href="custom.html"><img src="../../../../../doc/src/images/next.png" alt="Next"></a>
</div>
<div class="section">
<div class="titlepage"><div><div><h2 class="title" style="clear: both">
@@ -29,7 +29,7 @@
<p>
Performance measurements were taken using <code class="computeroutput"><span class="identifier">std</span><span class="special">::</span><span class="identifier">chrono</span><span class="special">::</span><span class="identifier">highresolution_clock</span></code>,
with overhead corrections. The code was compiled using the build options: variant
= release, optimization = speed <sup>[<a name="fiber.performance.f0" href="#ftn.fiber.performance.f0" class="footnote">8</a>]</sup>.
= release, optimization = speed <sup>[<a name="fiber.performance.f0" href="#ftn.fiber.performance.f0" class="footnote">7</a>]</sup>.
</p>
<p>
The columns labeled <span class="bold"><strong>fiber (atomics)</strong></span> were compiled
@@ -490,7 +490,7 @@
</p>
<p>
Numbers of the <a href="https://github.com/atemerev/skynet" target="_top">microbenchmark
<span class="emphasis"><em>syknet</em></span></a> from Alexander Temerev <sup>[<a name="fiber.performance.f1" href="#ftn.fiber.performance.f1" class="footnote">9</a>]</sup>:
<span class="emphasis"><em>syknet</em></span></a> from Alexander Temerev <sup>[<a name="fiber.performance.f1" href="#ftn.fiber.performance.f1" class="footnote">8</a>]</sup>:
</p>
<div class="table">
<a name="fiber.performance.performance_of_n_100000_actors_goroutines_fibers"></a><p class="title"><b>Table&#160;1.7.&#160;performance of N=100000 actors/goroutines/fibers</b></p>
@@ -560,10 +560,10 @@
</div>
<br class="table-break"><div class="footnotes">
<br><hr width="100" align="left">
<div class="footnote"><p><sup>[<a name="ftn.fiber.performance.f0" href="#fiber.performance.f0" class="para">8</a>] </sup>
<div class="footnote"><p><sup>[<a name="ftn.fiber.performance.f0" href="#fiber.performance.f0" class="para">7</a>] </sup>
Intel Core2 Q6700, x86_64, 3GHz
</p></div>
<div class="footnote"><p><sup>[<a name="ftn.fiber.performance.f1" href="#fiber.performance.f1" class="para">9</a>] </sup>
<div class="footnote"><p><sup>[<a name="ftn.fiber.performance.f1" href="#fiber.performance.f1" class="para">8</a>] </sup>
Intel Core2 Q6700, x86_64, 3GHz
</p></div>
</div>
@@ -578,7 +578,7 @@
</tr></table>
<hr>
<div class="spirit-nav">
<a accesskey="p" href="integration.html"><img src="../../../../../doc/src/images/prev.png" alt="Prev"></a><a accesskey="u" href="../index.html"><img src="../../../../../doc/src/images/up.png" alt="Up"></a><a accesskey="h" href="../index.html"><img src="../../../../../doc/src/images/home.png" alt="Home"></a><a accesskey="n" href="custom.html"><img src="../../../../../doc/src/images/next.png" alt="Next"></a>
<a accesskey="p" href="integration/deeper_dive_into___boost_asio__.html"><img src="../../../../../doc/src/images/prev.png" alt="Prev"></a><a accesskey="u" href="../index.html"><img src="../../../../../doc/src/images/up.png" alt="Up"></a><a accesskey="h" href="../index.html"><img src="../../../../../doc/src/images/home.png" alt="Home"></a><a accesskey="n" href="custom.html"><img src="../../../../../doc/src/images/next.png" alt="Next"></a>
</div>
</body>
</html>

View File

@@ -47,7 +47,7 @@
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.<sup>[<a name="fiber.rationale.f0" href="#ftn.fiber.rationale.f0" class="footnote">11</a>]</sup>.
because they need no scheduler.<sup>[<a name="fiber.rationale.f0" href="#ftn.fiber.rationale.f0" class="footnote">10</a>]</sup>.
</p>
<h4>
<a name="fiber.rationale.h1"></a>
@@ -86,10 +86,10 @@
may still be false. Spurious wakeup can happen repeatedly and is caused on
some multiprocessor systems where making <code class="computeroutput"><span class="identifier">std</span><span class="special">::</span><span class="identifier">condition_variable</span></code>
wakeup completely predictable would slow down all <code class="computeroutput"><span class="identifier">std</span><span class="special">::</span><span class="identifier">condition_variable</span></code>
operations.<sup>[<a name="fiber.rationale.f1" href="#ftn.fiber.rationale.f1" class="footnote">12</a>]</sup>
operations.<sup>[<a name="fiber.rationale.f1" href="#ftn.fiber.rationale.f1" class="footnote">11</a>]</sup>
</p>
<p>
<a class="link" href="synchronization/conditions.html#class_condition_variable"> <code class="computeroutput">condition_variable</code></a> is not subject to spurious wakeup.
<a class="link" href="synchronization/conditions.html#class_condition_variable"><code class="computeroutput">condition_variable</code></a> is not subject to spurious wakeup.
Nonetheless it is prudent to test the business-logic condition in a <code class="computeroutput"><span class="identifier">wait</span><span class="special">()</span></code> loop
&#8212; or, equivalently, use one of the <code class="computeroutput"><span class="identifier">wait</span><span class="special">(</span> <span class="identifier">lock</span><span class="special">,</span>
<span class="identifier">predicate</span> <span class="special">)</span></code>
@@ -105,7 +105,7 @@
</h4>
<p>
Support for migrating fibers between threads has been integrated. The user-defined
scheduler must call <a class="link" href="scheduling.html#context_migrate"> <code class="computeroutput">context::migrate()</code></a> on a fiber-context on
scheduler must call <a class="link" href="scheduling.html#context_migrate"><code class="computeroutput">context::migrate()</code></a> on a fiber-context on
the destination thread, passing <code class="computeroutput"><span class="identifier">migrate</span><span class="special">()</span></code> the fiber-context to migrate. (For more information
about custom schedulers, see <a class="link" href="custom.html#custom">Customization</a>.)
Examples <code class="computeroutput"><span class="identifier">work_sharing</span></code> and
@@ -122,11 +122,11 @@
for Boost.Asio</a>
</h4>
<p>
Support for <a href="http://www.boost.org/doc/libs/release/libs/asio/index.html" target="_top">Boost.Asio</a>'s
Support for <a href="http://www.boost.org/doc/libs/release/libs/asio/index.html" target="_top">Boost.Asio</a>&#8217;s
<span class="emphasis"><em>async-result</em></span> is not part of the official API. However,
to integrate with a <code class="computeroutput"><span class="identifier">boost</span><span class="special">::</span><span class="identifier">asio</span><span class="special">::</span><span class="identifier">io_service</span></code>,
to integrate with a <a href="http://www.boost.org/doc/libs/release/doc/html/boost_asio/reference/io_service.html" target="_top"><code class="computeroutput"><span class="identifier">boost</span><span class="special">::</span><span class="identifier">asio</span><span class="special">::</span><span class="identifier">io_service</span></code></a>,
see <a class="link" href="integration.html#integration">Sharing a Thread with Another Main Loop</a>.
To interface smoothly with an arbitrary Asio async I/O operation, see <a class="link" href="callbacks.html#callbacks_asio">Then There's <a href="http://www.boost.org/doc/libs/release/libs/asio/index.html" target="_top">Boost.Asio</a></a>.
To interface smoothly with an arbitrary Asio async I/O operation, see <a class="link" href="callbacks/then_there_s____boost_asio__.html#callbacks_asio">Then There&#8217;s <a href="http://www.boost.org/doc/libs/release/libs/asio/index.html" target="_top">Boost.Asio</a></a>.
</p>
<h4>
<a name="fiber.rationale.h6"></a>
@@ -147,11 +147,11 @@
</p>
<div class="footnotes">
<br><hr width="100" align="left">
<div class="footnote"><p><sup>[<a name="ftn.fiber.rationale.f0" href="#fiber.rationale.f0" class="para">11</a>] </sup>
<div class="footnote"><p><sup>[<a name="ftn.fiber.rationale.f0" href="#fiber.rationale.f0" class="para">10</a>] </sup>
<a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2014/n4024.pdf" target="_top">'N4024:
Distinguishing coroutines and fibers'</a>
</p></div>
<div class="footnote"><p><sup>[<a name="ftn.fiber.rationale.f1" href="#fiber.rationale.f1" class="para">12</a>] </sup>
<div class="footnote"><p><sup>[<a name="ftn.fiber.rationale.f1" href="#fiber.rationale.f1" class="para">11</a>] </sup>
David R. Butenhof <span class="quote">&#8220;<span class="quote">Programming with POSIX Threads</span>&#8221;</span>
</p></div>
</div>

View File

@@ -40,10 +40,10 @@
<p>
Each thread has its own scheduler. Different threads in a process may use different
schedulers. By default, <span class="bold"><strong>Boost.Fiber</strong></span> implicitly
instantiates <a class="link" href="scheduling.html#class_round_robin"> <code class="computeroutput">round_robin</code></a> as the scheduler for each thread.
instantiates <a class="link" href="scheduling.html#class_round_robin"><code class="computeroutput">round_robin</code></a> as the scheduler for each thread.
</p>
<p>
You are explicitly permitted to code your own <a class="link" href="scheduling.html#class_sched_algorithm"> <code class="computeroutput">sched_algorithm</code></a> subclass.
You are explicitly permitted to code your own <a class="link" href="scheduling.html#class_sched_algorithm"><code class="computeroutput">sched_algorithm</code></a> subclass.
For the most part, your <code class="computeroutput"><span class="identifier">sched_algorithm</span></code>
subclass need not defend against cross-thread calls: the fiber manager intercepts
and defers such calls. Most <code class="computeroutput"><span class="identifier">sched_algorithm</span></code>
@@ -52,7 +52,7 @@
</p>
<p>
Your <code class="computeroutput"><span class="identifier">sched_algorithm</span></code> subclass
is engaged on a particular thread by calling <a class="link" href="fiber_mgmt/fiber.html#use_scheduling_algorithm"> <code class="computeroutput">use_scheduling_algorithm()</code></a>:
is engaged on a particular thread by calling <a class="link" href="fiber_mgmt/fiber.html#use_scheduling_algorithm"><code class="computeroutput">use_scheduling_algorithm()</code></a>:
</p>
<pre class="programlisting"><span class="keyword">void</span> <span class="identifier">thread_fn</span><span class="special">()</span> <span class="special">{</span>
<span class="identifier">boost</span><span class="special">::</span><span class="identifier">fibers</span><span class="special">::</span><span class="identifier">use_scheduling_algorithm</span><span class="special">&lt;</span> <span class="identifier">my_fiber_scheduler</span> <span class="special">&gt;();</span>
@@ -60,8 +60,8 @@
<span class="special">}</span>
</pre>
<p>
A scheduler class must implement interface <a class="link" href="scheduling.html#class_sched_algorithm"> <code class="computeroutput">sched_algorithm</code></a>.
<span class="bold"><strong>Boost.Fiber</strong></span> provides one scheduler: <a class="link" href="scheduling.html#class_round_robin"> <code class="computeroutput">round_robin</code></a>.
A scheduler class must implement interface <a class="link" href="scheduling.html#class_sched_algorithm"><code class="computeroutput">sched_algorithm</code></a>.
<span class="bold"><strong>Boost.Fiber</strong></span> provides one scheduler: <a class="link" href="scheduling.html#class_round_robin"><code class="computeroutput">round_robin</code></a>.
</p>
<p>
</p>
@@ -113,7 +113,7 @@
Informs the scheduler that fiber <code class="computeroutput"><span class="identifier">f</span></code>
is ready to run. Fiber <code class="computeroutput"><span class="identifier">f</span></code>
might be newly launched, or it might have been blocked but has just been
awakened, or it might have called <a class="link" href="fiber_mgmt/this_fiber.html#this_fiber_yield"> <code class="computeroutput">this_fiber::yield()</code></a>.
awakened, or it might have called <a class="link" href="fiber_mgmt/this_fiber.html#this_fiber_yield"><code class="computeroutput">this_fiber::yield()</code></a>.
</p></dd>
<dt><span class="term">Note:</span></dt>
<dd><p>
@@ -123,7 +123,7 @@
</p></dd>
<dt><span class="term">See also:</span></dt>
<dd><p>
<a class="link" href="scheduling.html#class_round_robin"> <code class="computeroutput">round_robin</code></a>
<a class="link" href="scheduling.html#class_round_robin"><code class="computeroutput">round_robin</code></a>
</p></dd>
</dl>
</div>
@@ -155,7 +155,7 @@
</p></dd>
<dt><span class="term">See also:</span></dt>
<dd><p>
<a class="link" href="scheduling.html#class_round_robin"> <code class="computeroutput">round_robin</code></a>
<a class="link" href="scheduling.html#class_round_robin"><code class="computeroutput">round_robin</code></a>
</p></dd>
</dl>
</div>
@@ -206,12 +206,12 @@
environment in whatever way makes sense. The fiber manager is stating
that <code class="computeroutput"><span class="identifier">suspend_until</span><span class="special">()</span></code>
need not return until <code class="computeroutput"><span class="identifier">abs_time</span></code>
&#8212; or <a class="link" href="scheduling.html#sched_algorithm_notify"> <code class="computeroutput">sched_algorithm::notify()</code></a> is called &#8212; whichever
&#8212; or <a class="link" href="scheduling.html#sched_algorithm_notify"><code class="computeroutput">sched_algorithm::notify()</code></a> is called &#8212; whichever
comes first. The interaction with <code class="computeroutput"><span class="identifier">notify</span><span class="special">()</span></code> means that, for instance, calling
<a href="http://en.cppreference.com/w/cpp/thread/sleep_until" target="_top"><code class="computeroutput"><span class="identifier">std</span><span class="special">::</span><span class="identifier">this_thread</span><span class="special">::</span><span class="identifier">sleep_until</span><span class="special">(</span><span class="identifier">abs_time</span><span class="special">)</span></code></a>
would be too simplistic. <a class="link" href="scheduling.html#round_robin_suspend_until"> <code class="computeroutput">round_robin::suspend_until()</code></a> uses
would be too simplistic. <a class="link" href="scheduling.html#round_robin_suspend_until"><code class="computeroutput">round_robin::suspend_until()</code></a> uses
a <a href="http://en.cppreference.com/w/cpp/thread/condition_variable" target="_top"><code class="computeroutput"><span class="identifier">std</span><span class="special">::</span><span class="identifier">condition_variable</span></code></a> to coordinate
with <a class="link" href="scheduling.html#round_robin_notify"> <code class="computeroutput">round_robin::notify()</code></a>.
with <a class="link" href="scheduling.html#round_robin_notify"><code class="computeroutput">round_robin::notify()</code></a>.
</p></dd>
<dt><span class="term">Note:</span></dt>
<dd><p>
@@ -239,7 +239,7 @@
<dl>
<dt><span class="term">Effects:</span></dt>
<dd><p>
Requests the scheduler to return from a pending call to <a class="link" href="scheduling.html#sched_algorithm_suspend_until"> <code class="computeroutput">sched_algorithm::suspend_until()</code></a>.
Requests the scheduler to return from a pending call to <a class="link" href="scheduling.html#sched_algorithm_suspend_until"><code class="computeroutput">sched_algorithm::suspend_until()</code></a>.
</p></dd>
<dt><span class="term">Note:</span></dt>
<dd><p>
@@ -261,7 +261,7 @@
<p>
</p>
<p>
This class implements <a class="link" href="scheduling.html#class_sched_algorithm"> <code class="computeroutput">sched_algorithm</code></a>, scheduling fibers
This class implements <a class="link" href="scheduling.html#class_sched_algorithm"><code class="computeroutput">sched_algorithm</code></a>, scheduling fibers
in round-robin fashion.
</p>
<pre class="programlisting"><span class="preprocessor">#include</span> <span class="special">&lt;</span><span class="identifier">boost</span><span class="special">/</span><span class="identifier">fiber</span><span class="special">/</span><span class="identifier">round_robin</span><span class="special">.</span><span class="identifier">hpp</span><span class="special">&gt;</span>
@@ -406,7 +406,7 @@
<dl>
<dt><span class="term">Effects:</span></dt>
<dd><p>
Wake up a pending call to <a class="link" href="scheduling.html#round_robin_suspend_until"> <code class="computeroutput">round_robin::suspend_until()</code></a>,
Wake up a pending call to <a class="link" href="scheduling.html#round_robin_suspend_until"><code class="computeroutput">round_robin::suspend_until()</code></a>,
some fibers might be ready. This implementation wakes <code class="computeroutput"><span class="identifier">suspend_until</span><span class="special">()</span></code> via <a href="http://en.cppreference.com/w/cpp/thread/condition_variable/notify_all" target="_top"><code class="computeroutput"><span class="identifier">std</span><span class="special">::</span><span class="identifier">condition_variable</span><span class="special">::</span><span class="identifier">notify_all</span><span class="special">()</span></code></a>.
</p></dd>
<dt><span class="term">Throws:</span></dt>
@@ -421,8 +421,8 @@
Scheduler Fiber Properties</a>
</h4>
<p>
A scheduler class directly derived from <a class="link" href="scheduling.html#class_sched_algorithm"> <code class="computeroutput">sched_algorithm</code></a> can
use any information available from <a class="link" href="scheduling.html#class_context"> <code class="computeroutput">context</code></a> to implement the <code class="computeroutput"><span class="identifier">sched_algorithm</span></code> interface. But a custom scheduler
A scheduler class directly derived from <a class="link" href="scheduling.html#class_sched_algorithm"><code class="computeroutput">sched_algorithm</code></a> can
use any information available from <a class="link" href="scheduling.html#class_context"><code class="computeroutput">context</code></a> to implement the <code class="computeroutput"><span class="identifier">sched_algorithm</span></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.
</p>
@@ -495,8 +495,8 @@
<dl>
<dt><span class="term">Effects:</span></dt>
<dd><p>
Pass control to the custom <a class="link" href="scheduling.html#class_sched_algorithm_with_properties"> <code class="computeroutput">sched_algorithm_with_properties&lt;&gt;</code></a> subclass's
<a class="link" href="scheduling.html#sched_algorithm_with_properties_property_change"> <code class="computeroutput">sched_algorithm_with_properties::property_change()</code></a> method.
Pass control to the custom <a class="link" href="scheduling.html#class_sched_algorithm_with_properties"><code class="computeroutput">sched_algorithm_with_properties&lt;&gt;</code></a> subclass's
<a class="link" href="scheduling.html#sched_algorithm_with_properties_property_change"><code class="computeroutput">sched_algorithm_with_properties::property_change()</code></a> method.
</p></dd>
<dt><span class="term">Throws:</span></dt>
<dd><p>
@@ -504,8 +504,8 @@
</p></dd>
<dt><span class="term">Note:</span></dt>
<dd><p>
A custom scheduler's <a class="link" href="scheduling.html#sched_algorithm_with_properties_pick_next"> <code class="computeroutput">sched_algorithm_with_properties::pick_next()</code></a> method
might dynamically select from the ready fibers, or <a class="link" href="scheduling.html#sched_algorithm_with_properties_awakened"> <code class="computeroutput">sched_algorithm_with_properties::awakened()</code></a> might
A custom scheduler's <a class="link" href="scheduling.html#sched_algorithm_with_properties_pick_next"><code class="computeroutput">sched_algorithm_with_properties::pick_next()</code></a> method
might dynamically select from the ready fibers, or <a class="link" href="scheduling.html#sched_algorithm_with_properties_awakened"><code class="computeroutput">sched_algorithm_with_properties::awakened()</code></a> might
instead insert each ready fiber into some form of ready queue for <code class="computeroutput"><span class="identifier">pick_next</span><span class="special">()</span></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
@@ -534,7 +534,7 @@
<p>
A custom scheduler that depends on a custom properties class <code class="computeroutput"><span class="identifier">PROPS</span></code> should be derived from <code class="computeroutput"><span class="identifier">sched_algorithm_with_properties</span><span class="special">&lt;</span><span class="identifier">PROPS</span><span class="special">&gt;</span></code>.
<code class="computeroutput"><span class="identifier">PROPS</span></code> should be derived from
<a class="link" href="scheduling.html#class_fiber_properties"> <code class="computeroutput">fiber_properties</code></a>.
<a class="link" href="scheduling.html#class_fiber_properties"><code class="computeroutput">fiber_properties</code></a>.
</p>
<pre class="programlisting"><span class="preprocessor">#include</span> <span class="special">&lt;</span><span class="identifier">boost</span><span class="special">/</span><span class="identifier">fiber</span><span class="special">/</span><span class="identifier">algorithm</span><span class="special">.</span><span class="identifier">hpp</span><span class="special">&gt;</span>
@@ -575,7 +575,7 @@
<dt><span class="term">Effects:</span></dt>
<dd><p>
Informs the scheduler that fiber <code class="computeroutput"><span class="identifier">f</span></code>
is ready to run, like <a class="link" href="scheduling.html#sched_algorithm_awakened"> <code class="computeroutput">sched_algorithm::awakened()</code></a>.
is ready to run, like <a class="link" href="scheduling.html#sched_algorithm_awakened"><code class="computeroutput">sched_algorithm::awakened()</code></a>.
Passes the fiber's associated <code class="computeroutput"><span class="identifier">PROPS</span></code>
instance.
</p></dd>
@@ -616,7 +616,7 @@
</p></dd>
<dt><span class="term">Note:</span></dt>
<dd><p>
same as <a class="link" href="scheduling.html#sched_algorithm_pick_next"> <code class="computeroutput">sched_algorithm::pick_next()</code></a>
same as <a class="link" href="scheduling.html#sched_algorithm_pick_next"><code class="computeroutput">sched_algorithm::pick_next()</code></a>
</p></dd>
</dl>
</div>
@@ -646,7 +646,7 @@
</p></dd>
<dt><span class="term">Note:</span></dt>
<dd><p>
same as <a class="link" href="scheduling.html#sched_algorithm_has_ready_fibers"> <code class="computeroutput">sched_algorithm::has_ready_fibers()</code></a>
same as <a class="link" href="scheduling.html#sched_algorithm_has_ready_fibers"><code class="computeroutput">sched_algorithm::has_ready_fibers()</code></a>
</p></dd>
</dl>
</div>
@@ -671,7 +671,7 @@
</p></dd>
<dt><span class="term">Note:</span></dt>
<dd><p>
same as <a class="link" href="scheduling.html#sched_algorithm_suspend_until"> <code class="computeroutput">sched_algorithm::suspend_until()</code></a>
same as <a class="link" href="scheduling.html#sched_algorithm_suspend_until"><code class="computeroutput">sched_algorithm::suspend_until()</code></a>
</p></dd>
</dl>
</div>
@@ -692,11 +692,11 @@
<dl>
<dt><span class="term">Effects:</span></dt>
<dd><p>
Requests the scheduler to return from a pending call to <a class="link" href="scheduling.html#sched_algorithm_with_properties_suspend_until"> <code class="computeroutput">sched_algorithm_with_properties::suspend_until()</code></a>.
Requests the scheduler to return from a pending call to <a class="link" href="scheduling.html#sched_algorithm_with_properties_suspend_until"><code class="computeroutput">sched_algorithm_with_properties::suspend_until()</code></a>.
</p></dd>
<dt><span class="term">Note:</span></dt>
<dd><p>
same as <a class="link" href="scheduling.html#sched_algorithm_notify"> <code class="computeroutput">sched_algorithm::notify()</code></a>
same as <a class="link" href="scheduling.html#sched_algorithm_notify"><code class="computeroutput">sched_algorithm::notify()</code></a>
</p></dd>
</dl>
</div>
@@ -727,11 +727,11 @@
<dt><span class="term">Note:</span></dt>
<dd><p>
The fiber's associated <code class="computeroutput"><span class="identifier">PROPS</span></code>
instance is already passed to <a class="link" href="scheduling.html#sched_algorithm_with_properties_awakened"> <code class="computeroutput">sched_algorithm_with_properties::awakened()</code></a> and
<a class="link" href="scheduling.html#sched_algorithm_with_properties_property_change"> <code class="computeroutput">sched_algorithm_with_properties::property_change()</code></a>.
However, every <a class="link" href="scheduling.html#class_sched_algorithm"> <code class="computeroutput">sched_algorithm</code></a> subclass is expected
to track a collection of ready <a class="link" href="scheduling.html#class_context"> <code class="computeroutput">context</code></a> instances. This method
allows your custom scheduler to retrieve the <a class="link" href="scheduling.html#class_fiber_properties"> <code class="computeroutput">fiber_properties</code></a> subclass
instance is already passed to <a class="link" href="scheduling.html#sched_algorithm_with_properties_awakened"><code class="computeroutput">sched_algorithm_with_properties::awakened()</code></a> and
<a class="link" href="scheduling.html#sched_algorithm_with_properties_property_change"><code class="computeroutput">sched_algorithm_with_properties::property_change()</code></a>.
However, every <a class="link" href="scheduling.html#class_sched_algorithm"><code class="computeroutput">sched_algorithm</code></a> subclass is expected
to track a collection of ready <a class="link" href="scheduling.html#class_context"><code class="computeroutput">context</code></a> instances. This method
allows your custom scheduler to retrieve the <a class="link" href="scheduling.html#class_fiber_properties"><code class="computeroutput">fiber_properties</code></a> subclass
instance for any <code class="computeroutput"><span class="identifier">context</span></code>
in its collection.
</p></dd>
@@ -765,8 +765,8 @@
</p></dd>
<dt><span class="term">Note:</span></dt>
<dd><p>
This method is only called when a custom <a class="link" href="scheduling.html#class_fiber_properties"> <code class="computeroutput">fiber_properties</code></a> subclass
explicitly calls <a class="link" href="scheduling.html#fiber_properties_notify"> <code class="computeroutput">fiber_properties::notify()</code></a>.
This method is only called when a custom <a class="link" href="scheduling.html#class_fiber_properties"><code class="computeroutput">fiber_properties</code></a> subclass
explicitly calls <a class="link" href="scheduling.html#fiber_properties_notify"><code class="computeroutput">fiber_properties::notify()</code></a>.
</p></dd>
</dl>
</div>
@@ -787,7 +787,7 @@
<dl>
<dt><span class="term">Returns:</span></dt>
<dd><p>
A new instance of <a class="link" href="scheduling.html#class_fiber_properties"> <code class="computeroutput">fiber_properties</code></a> subclass <code class="computeroutput"><span class="identifier">PROPS</span></code>.
A new instance of <a class="link" href="scheduling.html#class_fiber_properties"><code class="computeroutput">fiber_properties</code></a> subclass <code class="computeroutput"><span class="identifier">PROPS</span></code>.
</p></dd>
<dt><span class="term">Note:</span></dt>
<dd><p>
@@ -819,10 +819,10 @@
<a name="ready_queue_t"></a>Of particular note is the fact that <code class="computeroutput"><span class="identifier">context</span></code> contains a hook to participate in
a <a href="http://www.boost.org/doc/libs/release/doc/html/intrusive/list.html" target="_top"><code class="computeroutput"><span class="identifier">boost</span><span class="special">::</span><span class="identifier">intrusive</span><span class="special">::</span><span class="identifier">list</span></code></a>
typedef'ed as <code class="computeroutput"><span class="identifier">boost</span><span class="special">::</span><span class="identifier">fibers</span><span class="special">::</span><span class="identifier">scheduler</span><span class="special">::</span><span class="identifier">ready_queue_t</span></code>. This hook is reserved for
use by <a class="link" href="scheduling.html#class_sched_algorithm"> <code class="computeroutput">sched_algorithm</code></a> implementations. (For instance,
<a class="link" href="scheduling.html#class_round_robin"> <code class="computeroutput">round_robin</code></a> contains a <code class="computeroutput"><span class="identifier">ready_queue_t</span></code>
instance to manage its ready fibers.) See <a class="link" href="scheduling.html#context_ready_is_linked"> <code class="computeroutput">context::ready_is_linked()</code></a>,
<a class="link" href="scheduling.html#context_ready_link"> <code class="computeroutput">context::ready_link()</code></a>, <a class="link" href="scheduling.html#context_ready_unlink"> <code class="computeroutput">context::ready_unlink()</code></a>.
use by <a class="link" href="scheduling.html#class_sched_algorithm"><code class="computeroutput">sched_algorithm</code></a> implementations. (For instance,
<a class="link" href="scheduling.html#class_round_robin"><code class="computeroutput">round_robin</code></a> contains a <code class="computeroutput"><span class="identifier">ready_queue_t</span></code>
instance to manage its ready fibers.) See <a class="link" href="scheduling.html#context_ready_is_linked"><code class="computeroutput">context::ready_is_linked()</code></a>,
<a class="link" href="scheduling.html#context_ready_link"><code class="computeroutput">context::ready_link()</code></a>, <a class="link" href="scheduling.html#context_ready_unlink"><code class="computeroutput">context::ready_unlink()</code></a>.
</p>
<p>
Your <code class="computeroutput"><span class="identifier">sched_algorithm</span></code> implementation
@@ -929,7 +929,7 @@
</p></dd>
<dt><span class="term">See also:</span></dt>
<dd><p>
<a class="link" href="fiber_mgmt/fiber.html#fiber_get_id"> <code class="computeroutput">fiber::get_id()</code></a>
<a class="link" href="fiber_mgmt/fiber.html#fiber_get_id"><code class="computeroutput">fiber::get_id()</code></a>
</p></dd>
</dl>
</div>
@@ -995,7 +995,7 @@
fiber is an implementation detail of the fiber manager. The context of
the <span class="quote">&#8220;<span class="quote">main</span>&#8221;</span> or <span class="quote">&#8220;<span class="quote">dispatching</span>&#8221;</span> fiber &#8212; any fiber
for which <code class="computeroutput"><span class="identifier">is_context</span><span class="special">(</span><span class="identifier">pinned_context</span><span class="special">)</span></code> is <code class="computeroutput"><span class="keyword">true</span></code>
&#8212; must never be passed to <a class="link" href="scheduling.html#context_migrate"> <code class="computeroutput">context::migrate()</code></a> for any other
&#8212; must never be passed to <a class="link" href="scheduling.html#context_migrate"><code class="computeroutput">context::migrate()</code></a> for any other
thread.
</p></dd>
</dl>
@@ -1047,7 +1047,7 @@
<dl>
<dt><span class="term">Returns:</span></dt>
<dd><p>
<code class="computeroutput"><span class="keyword">true</span></code> if <code class="computeroutput"><span class="special">*</span><span class="keyword">this</span></code> is stored in a <a class="link" href="scheduling.html#class_sched_algorithm"> <code class="computeroutput">sched_algorithm</code></a>
<code class="computeroutput"><span class="keyword">true</span></code> if <code class="computeroutput"><span class="special">*</span><span class="keyword">this</span></code> is stored in a <a class="link" href="scheduling.html#class_sched_algorithm"><code class="computeroutput">sched_algorithm</code></a>
implementation's
ready-queue.
</p></dd>
@@ -1057,7 +1057,7 @@ implementation's
</p></dd>
<dt><span class="term">Note:</span></dt>
<dd><p>
Specifically, this method indicates whether <a class="link" href="scheduling.html#context_ready_link"> <code class="computeroutput">context::ready_link()</code></a> has
Specifically, this method indicates whether <a class="link" href="scheduling.html#context_ready_link"><code class="computeroutput">context::ready_link()</code></a> has
been called on <code class="computeroutput"><span class="special">*</span><span class="keyword">this</span></code>.
<code class="computeroutput"><span class="identifier">ready_is_linked</span><span class="special">()</span></code>
has no information about participation in any other containers.
@@ -1092,8 +1092,8 @@ implementation's
<dd><p>
A <code class="computeroutput"><span class="identifier">context</span></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 a <a class="link" href="scheduling.html#class_sched_algorithm"> <code class="computeroutput">sched_algorithm</code></a> implementation
from cross-thread <a class="link" href="scheduling.html#sched_algorithm_awakened"> <code class="computeroutput">sched_algorithm::awakened()</code></a> calls.
This is the mechanism by which the fiber manager protects a <a class="link" href="scheduling.html#class_sched_algorithm"><code class="computeroutput">sched_algorithm</code></a> implementation
from cross-thread <a class="link" href="scheduling.html#sched_algorithm_awakened"><code class="computeroutput">sched_algorithm::awakened()</code></a> calls.
</p></dd>
</dl>
</div>
@@ -1246,7 +1246,7 @@ implementation's
<dt><span class="term">Effects:</span></dt>
<dd><p>
Removes <code class="computeroutput"><span class="special">*</span><span class="keyword">this</span></code>
from ready-queue: undoes the effect of <a class="link" href="scheduling.html#context_ready_link"> <code class="computeroutput">context::ready_link()</code></a>.
from ready-queue: undoes the effect of <a class="link" href="scheduling.html#context_ready_link"><code class="computeroutput">context::ready_link()</code></a>.
</p></dd>
<dt><span class="term">Throws:</span></dt>
<dd><p>
@@ -1322,7 +1322,7 @@ implementation's
<dl>
<dt><span class="term">Effects:</span></dt>
<dd><p>
Suspends the running fiber (the fiber associated with <code class="computeroutput"><span class="special">*</span><span class="keyword">this</span></code>) until some other fiber passes <code class="computeroutput"><span class="keyword">this</span></code> to <a class="link" href="scheduling.html#context_set_ready"> <code class="computeroutput">context::set_ready()</code></a>.
Suspends the running fiber (the fiber associated with <code class="computeroutput"><span class="special">*</span><span class="keyword">this</span></code>) until some other fiber passes <code class="computeroutput"><span class="keyword">this</span></code> to <a class="link" href="scheduling.html#context_set_ready"><code class="computeroutput">context::set_ready()</code></a>.
<code class="computeroutput"><span class="special">*</span><span class="keyword">this</span></code>
is marked as not-ready, and control passes to the scheduler to select
another fiber to run.
@@ -1364,8 +1364,8 @@ implementation's
Mark the fiber associated with context <code class="computeroutput"><span class="special">*</span><span class="identifier">ctx</span></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 <a class="link" href="scheduling.html#sched_algorithm_suspend_until"> <code class="computeroutput">sched_algorithm::suspend_until()</code></a>),
<a class="link" href="scheduling.html#sched_algorithm_notify"> <code class="computeroutput">sched_algorithm::notify()</code></a> is called to wake it up.
returned from a call to <a class="link" href="scheduling.html#sched_algorithm_suspend_until"><code class="computeroutput">sched_algorithm::suspend_until()</code></a>),
<a class="link" href="scheduling.html#sched_algorithm_notify"><code class="computeroutput">sched_algorithm::notify()</code></a> is called to wake it up.
</p></dd>
<dt><span class="term">Throws:</span></dt>
<dd><p>
@@ -1386,7 +1386,7 @@ implementation's
</p></dd>
<dt><span class="term">Note:</span></dt>
<dd><p>
See <a class="link" href="scheduling.html#context_migrate"> <code class="computeroutput">context::migrate()</code></a> for a way to migrate the suspended
See <a class="link" href="scheduling.html#context_migrate"><code class="computeroutput">context::migrate()</code></a> for a way to migrate the suspended
thread to the thread calling <code class="computeroutput"><span class="identifier">set_ready</span><span class="special">()</span></code>.
</p></dd>
</dl>

View File

@@ -27,14 +27,14 @@
<a name="fiber.stack"></a><a name="stack"></a><a class="link" href="stack.html" title="Stack allocation">Stack allocation</a>
</h2></div></div></div>
<p>
A <a class="link" href="fiber_mgmt/fiber.html#class_fiber"> <code class="computeroutput">fiber</code></a> uses internally an <a href="http://www.boost.org/doc/libs/release/libs/context/doc/html/context/econtext.html" target="_top"><span class="emphasis"><em>execution_context</em></span></a>
A <a class="link" href="fiber_mgmt/fiber.html#class_fiber"><code class="computeroutput">fiber</code></a> uses internally an <a href="http://www.boost.org/doc/libs/release/libs/context/doc/html/context/econtext.html" target="_top"><span class="emphasis"><em>execution_context</em></span></a>
which manages a set of registers and a stack. The memory used by the stack
is allocated/deallocated via a <span class="emphasis"><em>stack_allocator</em></span> which is
required to model a <a class="link" href="stack.html#stack_allocator_concept"><span class="emphasis"><em>stack-allocator
concept</em></span></a>.
</p>
<p>
A <span class="emphasis"><em>stack_allocator</em></span> can be passed to <a class="link" href="fiber_mgmt/fiber.html#fiber_fiber"><code class="computeroutput"><span class="identifier">fiber</span><span class="special">::</span><span class="identifier">fiber</span><span class="special">()</span></code></a> or to <a class="link" href="synchronization/futures/future.html#fibers_async"> <code class="computeroutput">fibers::async()</code></a>.
A <span class="emphasis"><em>stack_allocator</em></span> can be passed to <a class="link" href="fiber_mgmt/fiber.html#fiber_fiber"><code class="computeroutput"><span class="identifier">fiber</span><span class="special">::</span><span class="identifier">fiber</span><span class="special">()</span></code></a> or to <a class="link" href="synchronization/futures/future.html#fibers_async"><code class="computeroutput">fibers::async()</code></a>.
</p>
<a name="stack_allocator_concept"></a><h4>
<a name="fiber.stack.h0"></a>
@@ -170,7 +170,7 @@
<p>
</p>
<p>
<span class="bold"><strong>Boost.Fiber</strong></span> provides the class <a class="link" href="stack.html#class_protected_fixedsize_stack"> <code class="computeroutput">protected_fixedsize_stack</code></a> which
<span class="bold"><strong>Boost.Fiber</strong></span> provides the class <a class="link" href="stack.html#class_protected_fixedsize_stack"><code class="computeroutput">protected_fixedsize_stack</code></a> which
models the <a class="link" href="stack.html#stack_allocator_concept"><span class="emphasis"><em>stack-allocator
concept</em></span></a>. It appends a guard page at the end of each stack
to protect against exceeding the stack. If the guard page is accessed (read
@@ -183,10 +183,10 @@
<th align="left">Important</th>
</tr>
<tr><td align="left" valign="top"><p>
Using <a class="link" href="stack.html#class_protected_fixedsize_stack"> <code class="computeroutput">protected_fixedsize_stack</code></a> is expensive.
Using <a class="link" href="stack.html#class_protected_fixedsize_stack"><code class="computeroutput">protected_fixedsize_stack</code></a> 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 <a class="link" href="stack.html#class_fixedsize_stack"> <code class="computeroutput">fixedsize_stack</code></a>.
use as <a class="link" href="stack.html#class_fixedsize_stack"><code class="computeroutput">fixedsize_stack</code></a>.
</p></td></tr>
</table></div>
<div class="note"><table border="0" summary="Note">
@@ -280,9 +280,9 @@
<p>
</p>
<p>
<span class="bold"><strong>Boost.Fiber</strong></span> provides the class <a class="link" href="stack.html#class_pooled_fixedsize_stack"> <code class="computeroutput">pooled_fixedsize_stack</code></a> which
<span class="bold"><strong>Boost.Fiber</strong></span> provides the class <a class="link" href="stack.html#class_pooled_fixedsize_stack"><code class="computeroutput">pooled_fixedsize_stack</code></a> which
models the <a class="link" href="stack.html#stack_allocator_concept"><span class="emphasis"><em>stack-allocator
concept</em></span></a>. In contrast to <a class="link" href="stack.html#class_protected_fixedsize_stack"> <code class="computeroutput">protected_fixedsize_stack</code></a> it
concept</em></span></a>. In contrast to <a class="link" href="stack.html#class_protected_fixedsize_stack"><code class="computeroutput">protected_fixedsize_stack</code></a> it
does not append a guard page at the end of each stack. The memory is managed
internally by <a href="http://www.boost.org/doc/libs/release/libs/pool/doc/html/boost/pool.html" target="_top"><code class="computeroutput"><span class="identifier">boost</span><span class="special">::</span><span class="identifier">pool</span><span class="special">&lt;&gt;</span></code></a>.
</p>
@@ -399,9 +399,9 @@
<p>
</p>
<p>
<span class="bold"><strong>Boost.Fiber</strong></span> provides the class <a class="link" href="stack.html#class_fixedsize_stack"> <code class="computeroutput">fixedsize_stack</code></a> which
<span class="bold"><strong>Boost.Fiber</strong></span> provides the class <a class="link" href="stack.html#class_fixedsize_stack"><code class="computeroutput">fixedsize_stack</code></a> which
models the <a class="link" href="stack.html#stack_allocator_concept"><span class="emphasis"><em>stack-allocator
concept</em></span></a>. In contrast to <a class="link" href="stack.html#class_protected_fixedsize_stack"> <code class="computeroutput">protected_fixedsize_stack</code></a> it
concept</em></span></a>. In contrast to <a class="link" href="stack.html#class_protected_fixedsize_stack"><code class="computeroutput">protected_fixedsize_stack</code></a> it
does not append a guard page at the end of each stack. The memory is simply
managed by <code class="computeroutput"><span class="identifier">std</span><span class="special">::</span><span class="identifier">malloc</span><span class="special">()</span></code>
and <code class="computeroutput"><span class="identifier">std</span><span class="special">::</span><span class="identifier">free</span><span class="special">()</span></code>.
@@ -485,12 +485,12 @@
<p>
</p>
<p>
<span class="bold"><strong>Boost.Fiber</strong></span> supports usage of a <a class="link" href="stack.html#class_segmented_stack"> <code class="computeroutput">segmented_stack</code></a>,
<span class="bold"><strong>Boost.Fiber</strong></span> supports usage of a <a class="link" href="stack.html#class_segmented_stack"><code class="computeroutput">segmented_stack</code></a>,
i.e. the stack grows on demand. The fiber is created with a minimal stack size
which will be increased as required. Class <a class="link" href="stack.html#class_segmented_stack"> <code class="computeroutput">segmented_stack</code></a> models
which will be increased as required. Class <a class="link" href="stack.html#class_segmented_stack"><code class="computeroutput">segmented_stack</code></a> models
the <a class="link" href="stack.html#stack_allocator_concept"><span class="emphasis"><em>stack-allocator concept</em></span></a>.
In contrast to <a class="link" href="stack.html#class_protected_fixedsize_stack"> <code class="computeroutput">protected_fixedsize_stack</code></a> and
<a class="link" href="stack.html#class_fixedsize_stack"> <code class="computeroutput">fixedsize_stack</code></a> it creates a stack which grows on demand.
In contrast to <a class="link" href="stack.html#class_protected_fixedsize_stack"><code class="computeroutput">protected_fixedsize_stack</code></a> and
<a class="link" href="stack.html#class_fixedsize_stack"><code class="computeroutput">fixedsize_stack</code></a> it creates a stack which grows on demand.
</p>
<div class="note"><table border="0" summary="Note">
<tr>
@@ -501,7 +501,7 @@
Segmented stacks are currently only supported by <span class="bold"><strong>gcc</strong></span>
from version <span class="bold"><strong>4.7</strong></span> and <span class="bold"><strong>clang</strong></span>
from version <span class="bold"><strong>3.4</strong></span> onwards. In order to use
a <a class="link" href="stack.html#class_segmented_stack"> <code class="computeroutput">segmented_stack</code></a> <span class="bold"><strong>Boost.Fiber</strong></span>
a <a class="link" href="stack.html#class_segmented_stack"><code class="computeroutput">segmented_stack</code></a> <span class="bold"><strong>Boost.Fiber</strong></span>
must be built with property <code class="computeroutput"><span class="identifier">segmented</span><span class="special">-</span><span class="identifier">stacks</span></code>,
e.g. <span class="bold"><strong>toolset=gcc segmented-stacks=on</strong></span> at
b2/bjam command line.
@@ -581,7 +581,7 @@
<th align="left">Note</th>
</tr>
<tr><td align="left" valign="top"><p>
If the library is compiled for segmented stacks, <a class="link" href="stack.html#class_segmented_stack"> <code class="computeroutput">segmented_stack</code></a> is
If the library is compiled for segmented stacks, <a class="link" href="stack.html#class_segmented_stack"><code class="computeroutput">segmented_stack</code></a> is
the only available stack allocator.
</p></td></tr>
</table></div>

View File

@@ -39,7 +39,7 @@
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 class="computeroutput"><span class="identifier">barrier</span><span class="special">(</span><span class="number">2</span><span class="special">)</span></code> as the synchronization
mechanism, making each new fiber call its <a class="link" href="barriers.html#barrier_wait"> <code class="computeroutput">barrier::wait()</code></a> method,
mechanism, making each new fiber call its <a class="link" href="barriers.html#barrier_wait"><code class="computeroutput">barrier::wait()</code></a> method,
then calling <code class="computeroutput"><span class="identifier">wait</span><span class="special">()</span></code>
in the launching fiber to wait until the first other fiber completes.
</p>
@@ -83,7 +83,7 @@
It is unwise to tie the lifespan of a barrier to any one of its participating
fibers. Although conceptually all waiting fibers awaken <span class="quote">&#8220;<span class="quote">simultaneously,</span>&#8221;</span>
because of the nature of fibers, in practice they will awaken one by one
in indeterminate order.<sup>[<a name="fiber.synchronization.barriers.f0" href="#ftn.fiber.synchronization.barriers.f0" class="footnote">2</a>]</sup> The rest of the waiting fibers will still be blocked in <code class="computeroutput"><span class="identifier">wait</span><span class="special">()</span></code>,
in indeterminate order.<sup>[<a name="fiber.synchronization.barriers.f0" href="#ftn.fiber.synchronization.barriers.f0" class="footnote">1</a>]</sup> The rest of the waiting fibers will still be blocked in <code class="computeroutput"><span class="identifier">wait</span><span class="special">()</span></code>,
which must, before returning, access data members in the barrier object.
</p></td></tr>
</table></div>
@@ -109,7 +109,7 @@
<span class="special">};</span>
</pre>
<p>
Instances of <a class="link" href="barriers.html#class_barrier"> <code class="computeroutput">barrier</code></a> are not copyable or movable.
Instances of <a class="link" href="barriers.html#class_barrier"><code class="computeroutput">barrier</code></a> are not copyable or movable.
</p>
<h5>
<a name="fiber.synchronization.barriers.h0"></a>
@@ -168,16 +168,11 @@
<dd><p>
<code class="computeroutput"><span class="identifier">fiber_error</span></code>
</p></dd>
<dt><span class="term">Notes:</span></dt>
<dd><p>
<code class="computeroutput"><span class="identifier">wait</span><span class="special">()</span></code>
is one of the predefined <a class="link" href="../fiber_mgmt.html#interruption"><span class="emphasis"><em>interruption-points</em></span></a>.
</p></dd>
</dl>
</div>
<div class="footnotes">
<br><hr width="100" align="left">
<div class="footnote"><p><sup>[<a name="ftn.fiber.synchronization.barriers.f0" href="#fiber.synchronization.barriers.f0" class="para">2</a>] </sup>
<div class="footnote"><p><sup>[<a name="ftn.fiber.synchronization.barriers.f0" href="#fiber.synchronization.barriers.f0" class="para">1</a>] </sup>
The current implementation wakes fibers in FIFO order: the first to call
<code class="computeroutput"><span class="identifier">wait</span><span class="special">()</span></code>
wakes first, and so forth. But it is perilous to rely on the order in

View File

@@ -289,7 +289,7 @@
</p></dd>
<dt><span class="term">Throws:</span></dt>
<dd><p>
<code class="computeroutput"><span class="identifier">fiber_interrupted</span></code>
Nothing
</p></dd>
</dl>
</div>
@@ -317,7 +317,7 @@
<dt><span class="term">Throws:</span></dt>
<dd><p>
<code class="computeroutput"><span class="identifier">fiber_error</span></code> if <code class="computeroutput"><span class="special">*</span><span class="keyword">this</span></code>
is closed or <code class="computeroutput"><span class="identifier">fiber_interrupted</span></code>
is closed
</p></dd>
<dt><span class="term">Error conditions:</span></dt>
<dd><p>
@@ -387,7 +387,6 @@
</p></dd>
<dt><span class="term">Throws:</span></dt>
<dd><p>
<code class="computeroutput"><span class="identifier">fiber_interrupted</span></code> or
timeout-related exceptions.
</p></dd>
</dl>
@@ -426,7 +425,6 @@
</p></dd>
<dt><span class="term">Throws:</span></dt>
<dd><p>
<code class="computeroutput"><span class="identifier">fiber_interrupted</span></code> or
timeout-related exceptions.
</p></dd>
</dl>
@@ -656,7 +654,6 @@
</p></dd>
<dt><span class="term">Throws:</span></dt>
<dd><p>
<code class="computeroutput"><span class="identifier">fiber_interrupted</span></code> or
exceptions thrown by memory allocation and copying or moving <code class="computeroutput"><span class="identifier">va</span></code>.
</p></dd>
</dl>
@@ -699,7 +696,6 @@
</p></dd>
<dt><span class="term">Throws:</span></dt>
<dd><p>
<code class="computeroutput"><span class="identifier">fiber_interrupted</span></code>,
exceptions thrown by memory allocation and copying or moving <code class="computeroutput"><span class="identifier">va</span></code> or timeout-related exceptions.
</p></dd>
</dl>
@@ -744,7 +740,6 @@
</p></dd>
<dt><span class="term">Throws:</span></dt>
<dd><p>
<code class="computeroutput"><span class="identifier">fiber_interrupted</span></code> or
exceptions thrown by memory allocation and copying or moving <code class="computeroutput"><span class="identifier">va</span></code> or timeout-related exceptions.
</p></dd>
</dl>
@@ -809,7 +804,7 @@
</p></dd>
<dt><span class="term">Throws:</span></dt>
<dd><p>
<code class="computeroutput"><span class="identifier">fiber_interrupted</span></code>
Nothing
</p></dd>
</dl>
</div>
@@ -839,7 +834,7 @@
<dt><span class="term">Throws:</span></dt>
<dd><p>
<code class="computeroutput"><span class="identifier">fiber_error</span></code> if <code class="computeroutput"><span class="special">*</span><span class="keyword">this</span></code>
is closed or <code class="computeroutput"><span class="identifier">fiber_interrupted</span></code>
is closed
</p></dd>
<dt><span class="term">Error conditions:</span></dt>
<dd><p>
@@ -915,7 +910,6 @@
</p></dd>
<dt><span class="term">Throws:</span></dt>
<dd><p>
<code class="computeroutput"><span class="identifier">fiber_interrupted</span></code> or
timeout-related exceptions.
</p></dd>
</dl>
@@ -957,7 +951,6 @@
</p></dd>
<dt><span class="term">Throws:</span></dt>
<dd><p>
<code class="computeroutput"><span class="identifier">fiber_interrupted</span></code> or
timeout-related exceptions.
</p></dd>
</dl>

View File

@@ -39,7 +39,7 @@
<span class="keyword">class</span> <span class="identifier">condition_variable_any</span><span class="special">;</span>
</pre>
<p>
The class <a class="link" href="conditions.html#class_condition_variable"> <code class="computeroutput">condition_variable</code></a> provides a mechanism
The class <a class="link" href="conditions.html#class_condition_variable"><code class="computeroutput">condition_variable</code></a> 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
@@ -64,8 +64,8 @@
</pre>
<p>
Notice that the <code class="computeroutput"><span class="identifier">lk</span></code> is passed
to <a class="link" href="conditions.html#condition_variable_wait"> <code class="computeroutput">condition_variable::wait()</code></a>: <code class="computeroutput"><span class="identifier">wait</span><span class="special">()</span></code> will atomically add the fiber to the set
of fibers waiting on the condition variable, and unlock the <a class="link" href="mutex_types.html#class_mutex"> <code class="computeroutput">mutex</code></a>.
to <a class="link" href="conditions.html#condition_variable_wait"><code class="computeroutput">condition_variable::wait()</code></a>: <code class="computeroutput"><span class="identifier">wait</span><span class="special">()</span></code> will atomically add the fiber to the set
of fibers waiting on the condition variable, and unlock the <a class="link" href="mutex_types.html#class_mutex"><code class="computeroutput">mutex</code></a>.
When the fiber is awakened, the <code class="computeroutput"><span class="identifier">mutex</span></code>
will be locked again before the call to <code class="computeroutput"><span class="identifier">wait</span><span class="special">()</span></code> returns. This allows other fibers to acquire
the <code class="computeroutput"><span class="identifier">mutex</span></code> in order to update
@@ -87,8 +87,8 @@
<p>
In the meantime, another fiber sets <code class="computeroutput"><span class="identifier">data_ready</span></code>
to <code class="computeroutput"><span class="keyword">true</span></code>, and then calls either
<a class="link" href="conditions.html#condition_variable_notify_one"> <code class="computeroutput">condition_variable::notify_one()</code></a> or <a class="link" href="conditions.html#condition_variable_notify_all"> <code class="computeroutput">condition_variable::notify_all()</code></a> on
the <a class="link" href="conditions.html#class_condition_variable"> <code class="computeroutput">condition_variable</code></a> <code class="computeroutput"><span class="identifier">cond</span></code>
<a class="link" href="conditions.html#condition_variable_notify_one"><code class="computeroutput">condition_variable::notify_one()</code></a> or <a class="link" href="conditions.html#condition_variable_notify_all"><code class="computeroutput">condition_variable::notify_all()</code></a> on
the <a class="link" href="conditions.html#class_condition_variable"><code class="computeroutput">condition_variable</code></a> <code class="computeroutput"><span class="identifier">cond</span></code>
to wake one waiting fiber or all the waiting fibers respectively.
</p>
<pre class="programlisting"><span class="keyword">void</span> <span class="identifier">retrieve_data</span><span class="special">();</span>
@@ -105,18 +105,18 @@
<span class="special">}</span>
</pre>
<p>
Note that the same <a class="link" href="mutex_types.html#class_mutex"> <code class="computeroutput">mutex</code></a> is locked before the shared data is updated,
Note that the same <a class="link" href="mutex_types.html#class_mutex"><code class="computeroutput">mutex</code></a> is locked before the shared data is updated,
but that the <code class="computeroutput"><span class="identifier">mutex</span></code> does not
have to be locked across the call to <a class="link" href="conditions.html#condition_variable_notify_one"> <code class="computeroutput">condition_variable::notify_one()</code></a>.
have to be locked across the call to <a class="link" href="conditions.html#condition_variable_notify_one"><code class="computeroutput">condition_variable::notify_one()</code></a>.
</p>
<p>
Locking is important because the synchronization objects provided by <span class="bold"><strong>Boost.Fiber</strong></span> can be used to synchronize fibers running
on different threads.
</p>
<p>
<span class="bold"><strong>Boost.Fiber</strong></span> provides both <a class="link" href="conditions.html#class_condition_variable"> <code class="computeroutput">condition_variable</code></a> and
<a class="link" href="conditions.html#class_condition_variable_any"> <code class="computeroutput">condition_variable_any</code></a>. <code class="computeroutput"><span class="identifier">boost</span><span class="special">::</span><span class="identifier">fibers</span><span class="special">::</span><span class="identifier">condition_variable</span></code>
can only wait on <a href="http://en.cppreference.com/w/cpp/thread/unique_lock" target="_top"><code class="computeroutput"><span class="identifier">std</span><span class="special">::</span><span class="identifier">unique_lock</span></code></a><code class="computeroutput"><span class="special">&lt;</span> <span class="identifier">boost</span><span class="special">::</span><span class="identifier">fibers</span><span class="special">::</span></code> <a class="link" href="mutex_types.html#class_mutex"> <code class="computeroutput">mutex</code></a><code class="computeroutput"> <span class="special">&gt;</span></code>
<span class="bold"><strong>Boost.Fiber</strong></span> provides both <a class="link" href="conditions.html#class_condition_variable"><code class="computeroutput">condition_variable</code></a> and
<a class="link" href="conditions.html#class_condition_variable_any"><code class="computeroutput">condition_variable_any</code></a>. <code class="computeroutput"><span class="identifier">boost</span><span class="special">::</span><span class="identifier">fibers</span><span class="special">::</span><span class="identifier">condition_variable</span></code>
can only wait on <a href="http://en.cppreference.com/w/cpp/thread/unique_lock" target="_top"><code class="computeroutput"><span class="identifier">std</span><span class="special">::</span><span class="identifier">unique_lock</span></code></a><code class="computeroutput"><span class="special">&lt;</span> <span class="identifier">boost</span><span class="special">::</span><span class="identifier">fibers</span><span class="special">::</span></code><a class="link" href="mutex_types.html#class_mutex"><code class="computeroutput">mutex</code></a><code class="computeroutput"> <span class="special">&gt;</span></code>
while <code class="computeroutput"><span class="identifier">boost</span><span class="special">::</span><span class="identifier">fibers</span><span class="special">::</span><span class="identifier">condition_variable_any</span></code> can wait on user-defined
lock types.
</p>
@@ -126,10 +126,10 @@
Wakeups</a>
</h5>
<p>
Neither <a class="link" href="conditions.html#class_condition_variable"> <code class="computeroutput">condition_variable</code></a> nor <a class="link" href="conditions.html#class_condition_variable_any"> <code class="computeroutput">condition_variable_any</code></a> are
subject to spurious wakeup: <a class="link" href="conditions.html#condition_variable_wait"> <code class="computeroutput">condition_variable::wait()</code></a> can
only wake up when <a class="link" href="conditions.html#condition_variable_notify_one"> <code class="computeroutput">condition_variable::notify_one()</code></a> or
<a class="link" href="conditions.html#condition_variable_notify_all"> <code class="computeroutput">condition_variable::notify_all()</code></a> is called. Even
Neither <a class="link" href="conditions.html#class_condition_variable"><code class="computeroutput">condition_variable</code></a> nor <a class="link" href="conditions.html#class_condition_variable_any"><code class="computeroutput">condition_variable_any</code></a> are
subject to spurious wakeup: <a class="link" href="conditions.html#condition_variable_wait"><code class="computeroutput">condition_variable::wait()</code></a> can
only wake up when <a class="link" href="conditions.html#condition_variable_notify_one"><code class="computeroutput">condition_variable::notify_one()</code></a> or
<a class="link" href="conditions.html#condition_variable_notify_all"><code class="computeroutput">condition_variable::notify_all()</code></a> is called. Even
so, it is prudent to use one of the <code class="computeroutput"><span class="identifier">wait</span><span class="special">(</span> <span class="identifier">lock</span><span class="special">,</span> <span class="identifier">predicate</span> <span class="special">)</span></code> overloads.
</p>
<p>
@@ -142,11 +142,11 @@
</p>
<p>
Because producer fibers might <a href="http://en.cppreference.com/w/cpp/container/queue/push" target="_top"><code class="computeroutput"><span class="identifier">push</span><span class="special">()</span></code></a>
items to the queue in bursts, they call <a class="link" href="conditions.html#condition_variable_notify_all"> <code class="computeroutput">condition_variable::notify_all()</code></a> rather
than <a class="link" href="conditions.html#condition_variable_notify_one"> <code class="computeroutput">condition_variable::notify_one()</code></a>.
items to the queue in bursts, they call <a class="link" href="conditions.html#condition_variable_notify_all"><code class="computeroutput">condition_variable::notify_all()</code></a> rather
than <a class="link" href="conditions.html#condition_variable_notify_one"><code class="computeroutput">condition_variable::notify_one()</code></a>.
</p>
<p>
But a given consumer fiber might well wake up from <a class="link" href="conditions.html#condition_variable_wait"> <code class="computeroutput">condition_variable::wait()</code></a> and
But a given consumer fiber might well wake up from <a class="link" href="conditions.html#condition_variable_wait"><code class="computeroutput">condition_variable::wait()</code></a> and
find the queue <code class="computeroutput"><span class="identifier">empty</span><span class="special">()</span></code>,
because other consumer fibers might already have processed all pending items.
</p>
@@ -408,9 +408,7 @@
<dt><span class="term">Throws:</span></dt>
<dd><p>
<code class="computeroutput"><span class="identifier">fiber_error</span></code> if an error
occurs, <code class="computeroutput"><span class="identifier">fiber_interrupted</span></code>
if the wait was interrupted by a call to <a class="link" href="../fiber_mgmt/fiber.html#fiber_interrupt"> <code class="computeroutput">fiber::interrupt()</code></a> on
the <a class="link" href="../fiber_mgmt/fiber.html#class_fiber"> <code class="computeroutput">fiber</code></a> object associated with the current fiber of execution.
occurs.
</p></dd>
<dt><span class="term">Note:</span></dt>
<dd><p>
@@ -418,7 +416,7 @@
concurrently calling <code class="computeroutput"><span class="identifier">wait</span></code>
on <code class="computeroutput"><span class="special">*</span><span class="keyword">this</span></code>
must wait on <code class="computeroutput"><span class="identifier">lk</span></code> objects
governing the <span class="emphasis"><em>same</em></span> <a class="link" href="mutex_types.html#class_mutex"> <code class="computeroutput">mutex</code></a>. Three distinct
governing the <span class="emphasis"><em>same</em></span> <a class="link" href="mutex_types.html#class_mutex"><code class="computeroutput">mutex</code></a>. Three distinct
objects are involved in any <code class="computeroutput">condition_variable_any::wait()</code> call: the
<code class="computeroutput">condition_variable_any</code> itself, the <code class="computeroutput"><span class="identifier">mutex</span></code>
coordinating access between fibers and a local lock object (e.g. <a href="http://en.cppreference.com/w/cpp/thread/unique_lock" target="_top"><code class="computeroutput"><span class="identifier">std</span><span class="special">::</span><span class="identifier">unique_lock</span></code></a>). In general,
@@ -495,10 +493,7 @@
<dt><span class="term">Throws:</span></dt>
<dd><p>
<code class="computeroutput"><span class="identifier">fiber_error</span></code> if an error
occurs, <code class="computeroutput"><span class="identifier">fiber_interrupted</span></code>
if the wait was interrupted by a call to <a class="link" href="../fiber_mgmt/fiber.html#fiber_interrupt"> <code class="computeroutput">fiber::interrupt()</code></a> on
the <a class="link" href="../fiber_mgmt/fiber.html#class_fiber"> <code class="computeroutput">fiber</code></a> object associated with the current fiber of execution
or timeout-related exceptions.
occurs or timeout-related exceptions.
</p></dd>
<dt><span class="term">Returns:</span></dt>
<dd><p>
@@ -518,7 +513,7 @@
</p></dd>
<dt><span class="term">Note:</span></dt>
<dd><p>
See <span class="bold"><strong>Note</strong></span> for <a class="link" href="conditions.html#condition_variable_any_wait"> <code class="computeroutput">condition_variable_any::wait()</code></a>.
See <span class="bold"><strong>Note</strong></span> for <a class="link" href="conditions.html#condition_variable_any_wait"><code class="computeroutput">condition_variable_any::wait()</code></a>.
</p></dd>
</dl>
</div>
@@ -588,10 +583,7 @@
<dt><span class="term">Throws:</span></dt>
<dd><p>
<code class="computeroutput"><span class="identifier">fiber_error</span></code> if an error
occurs, <code class="computeroutput"><span class="identifier">fiber_interrupted</span></code>
if the wait was interrupted by a call to <a class="link" href="../fiber_mgmt/fiber.html#fiber_interrupt"> <code class="computeroutput">fiber::interrupt()</code></a> on
the <a class="link" href="../fiber_mgmt/fiber.html#class_fiber"> <code class="computeroutput">fiber</code></a> object associated with the current fiber of execution
or timeout-related exceptions.
occurs or timeout-related exceptions.
</p></dd>
<dt><span class="term">Returns:</span></dt>
<dd><p>
@@ -611,7 +603,7 @@
</p></dd>
<dt><span class="term">Note:</span></dt>
<dd><p>
See <span class="bold"><strong>Note</strong></span> for <a class="link" href="conditions.html#condition_variable_any_wait"> <code class="computeroutput">condition_variable_any::wait()</code></a>.
See <span class="bold"><strong>Note</strong></span> for <a class="link" href="conditions.html#condition_variable_any_wait"><code class="computeroutput">condition_variable_any::wait()</code></a>.
</p></dd>
</dl>
</div>
@@ -828,9 +820,7 @@
<dt><span class="term">Throws:</span></dt>
<dd><p>
<code class="computeroutput"><span class="identifier">fiber_error</span></code> if an error
occurs, <code class="computeroutput"><span class="identifier">fiber_interrupted</span></code>
if the wait was interrupted by a call to <a class="link" href="../fiber_mgmt/fiber.html#fiber_interrupt"> <code class="computeroutput">fiber::interrupt()</code></a> on
the <a class="link" href="../fiber_mgmt/fiber.html#class_fiber"> <code class="computeroutput">fiber</code></a> object associated with the current fiber of execution.
occurs.
</p></dd>
<dt><span class="term">Note:</span></dt>
<dd><p>
@@ -838,7 +828,7 @@
concurrently calling <code class="computeroutput"><span class="identifier">wait</span></code>
on <code class="computeroutput"><span class="special">*</span><span class="keyword">this</span></code>
must wait on <code class="computeroutput"><span class="identifier">lk</span></code> objects
governing the <span class="emphasis"><em>same</em></span> <a class="link" href="mutex_types.html#class_mutex"> <code class="computeroutput">mutex</code></a>. Three distinct
governing the <span class="emphasis"><em>same</em></span> <a class="link" href="mutex_types.html#class_mutex"><code class="computeroutput">mutex</code></a>. Three distinct
objects are involved in any <code class="computeroutput">condition_variable::wait()</code> call: the <code class="computeroutput">condition_variable</code> itself,
the <code class="computeroutput"><span class="identifier">mutex</span></code> coordinating
access between fibers and a local lock object (e.g. <a href="http://en.cppreference.com/w/cpp/thread/unique_lock" target="_top"><code class="computeroutput"><span class="identifier">std</span><span class="special">::</span><span class="identifier">unique_lock</span></code></a>). In general,
@@ -915,10 +905,7 @@
<dt><span class="term">Throws:</span></dt>
<dd><p>
<code class="computeroutput"><span class="identifier">fiber_error</span></code> if an error
occurs, <code class="computeroutput"><span class="identifier">fiber_interrupted</span></code>
if the wait was interrupted by a call to <a class="link" href="../fiber_mgmt/fiber.html#fiber_interrupt"> <code class="computeroutput">fiber::interrupt()</code></a> on
the <a class="link" href="../fiber_mgmt/fiber.html#class_fiber"> <code class="computeroutput">fiber</code></a> object associated with the current fiber of execution
or timeout-related exceptions.
occurs or timeout-related exceptions.
</p></dd>
<dt><span class="term">Returns:</span></dt>
<dd><p>
@@ -938,7 +925,7 @@
</p></dd>
<dt><span class="term">Note:</span></dt>
<dd><p>
See <span class="bold"><strong>Note</strong></span> for <a class="link" href="conditions.html#condition_variable_wait"> <code class="computeroutput">condition_variable::wait()</code></a>.
See <span class="bold"><strong>Note</strong></span> for <a class="link" href="conditions.html#condition_variable_wait"><code class="computeroutput">condition_variable::wait()</code></a>.
</p></dd>
</dl>
</div>
@@ -1008,10 +995,7 @@
<dt><span class="term">Throws:</span></dt>
<dd><p>
<code class="computeroutput"><span class="identifier">fiber_error</span></code> if an error
occurs, <code class="computeroutput"><span class="identifier">fiber_interrupted</span></code>
if the wait was interrupted by a call to <a class="link" href="../fiber_mgmt/fiber.html#fiber_interrupt"> <code class="computeroutput">fiber::interrupt()</code></a> on
the <a class="link" href="../fiber_mgmt/fiber.html#class_fiber"> <code class="computeroutput">fiber</code></a> object associated with the current fiber of execution
or timeout-related exceptions.
occurs or timeout-related exceptions.
</p></dd>
<dt><span class="term">Returns:</span></dt>
<dd><p>
@@ -1031,7 +1015,7 @@
</p></dd>
<dt><span class="term">Note:</span></dt>
<dd><p>
See <span class="bold"><strong>Note</strong></span> for <a class="link" href="conditions.html#condition_variable_wait"> <code class="computeroutput">condition_variable::wait()</code></a>.
See <span class="bold"><strong>Note</strong></span> for <a class="link" href="conditions.html#condition_variable_wait"><code class="computeroutput">condition_variable::wait()</code></a>.
</p></dd>
</dl>
</div>

View File

@@ -43,34 +43,34 @@
in response to external stimuli, or on-demand.
</p>
<p>
This is done through the provision of four class templates: <a class="link" href="futures/future.html#class_future"> <code class="computeroutput">future&lt;&gt;</code></a> and
<a class="link" href="futures/future.html#class_shared_future"> <code class="computeroutput">shared_future&lt;&gt;</code></a> which are used to retrieve the asynchronous
results, and <a class="link" href="futures/promise.html#class_promise"> <code class="computeroutput">promise&lt;&gt;</code></a> and <a class="link" href="futures/packaged_task.html#class_packaged_task"> <code class="computeroutput">packaged_task&lt;&gt;</code></a> which
This is done through the provision of four class templates: <a class="link" href="futures/future.html#class_future"><code class="computeroutput">future&lt;&gt;</code></a> and
<a class="link" href="futures/future.html#class_shared_future"><code class="computeroutput">shared_future&lt;&gt;</code></a> which are used to retrieve the asynchronous
results, and <a class="link" href="futures/promise.html#class_promise"><code class="computeroutput">promise&lt;&gt;</code></a> and <a class="link" href="futures/packaged_task.html#class_packaged_task"><code class="computeroutput">packaged_task&lt;&gt;</code></a> which
are used to generate the asynchronous results.
</p>
<p>
An instance of <a class="link" href="futures/future.html#class_future"> <code class="computeroutput">future&lt;&gt;</code></a> holds the one and only reference
An instance of <a class="link" href="futures/future.html#class_future"><code class="computeroutput">future&lt;&gt;</code></a> 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 <a class="link" href="futures/future.html#future_get"> <code class="computeroutput">future::get()</code></a> by rvalue-reference to allow the result
returned from <a class="link" href="futures/future.html#future_get"><code class="computeroutput">future::get()</code></a> by rvalue-reference to allow the result
to be moved or copied as appropriate for the type.
</p>
<p>
On the other hand, many instances of <a class="link" href="futures/future.html#class_shared_future"> <code class="computeroutput">shared_future&lt;&gt;</code></a> may
On the other hand, many instances of <a class="link" href="futures/future.html#class_shared_future"><code class="computeroutput">shared_future&lt;&gt;</code></a> may
reference the same result. Instances can be freely copied and assigned, and
<a class="link" href="futures/future.html#shared_future_get"> <code class="computeroutput">shared_future::get()</code></a>
<a class="link" href="futures/future.html#shared_future_get"><code class="computeroutput">shared_future::get()</code></a>
returns a <code class="computeroutput"><span class="keyword">const</span></code>
reference so that multiple calls to <a class="link" href="futures/future.html#shared_future_get"> <code class="computeroutput">shared_future::get()</code></a>
reference so that multiple calls to <a class="link" href="futures/future.html#shared_future_get"><code class="computeroutput">shared_future::get()</code></a>
are
safe. You can move an instance of <a class="link" href="futures/future.html#class_future"> <code class="computeroutput">future&lt;&gt;</code></a> into an instance
of <a class="link" href="futures/future.html#class_shared_future"> <code class="computeroutput">shared_future&lt;&gt;</code></a>, thus transferring ownership
safe. You can move an instance of <a class="link" href="futures/future.html#class_future"><code class="computeroutput">future&lt;&gt;</code></a> into an instance
of <a class="link" href="futures/future.html#class_shared_future"><code class="computeroutput">shared_future&lt;&gt;</code></a>, thus transferring ownership
of the associated asynchronous result, but not vice-versa.
</p>
<p>
<a class="link" href="futures/future.html#fibers_async"> <code class="computeroutput">fibers::async()</code></a> is a simple way of running asynchronous tasks.
<a class="link" href="futures/future.html#fibers_async"><code class="computeroutput">fibers::async()</code></a> is a simple way of running asynchronous tasks.
A call to <code class="computeroutput"><span class="identifier">async</span><span class="special">()</span></code>
spawns a fiber and returns a <a class="link" href="futures/future.html#class_future"> <code class="computeroutput">future&lt;&gt;</code></a> that will deliver
spawns a fiber and returns a <a class="link" href="futures/future.html#class_future"><code class="computeroutput">future&lt;&gt;</code></a> that will deliver
the result of the fiber function.
</p>
<h5>
@@ -79,15 +79,15 @@ are
asynchronous values</a>
</h5>
<p>
You can set the value in a future with either a <a class="link" href="futures/promise.html#class_promise"> <code class="computeroutput">promise&lt;&gt;</code></a> or
a <a class="link" href="futures/packaged_task.html#class_packaged_task"> <code class="computeroutput">packaged_task&lt;&gt;</code></a>. A <a class="link" href="futures/packaged_task.html#class_packaged_task"> <code class="computeroutput">packaged_task&lt;&gt;</code></a> is
You can set the value in a future with either a <a class="link" href="futures/promise.html#class_promise"><code class="computeroutput">promise&lt;&gt;</code></a> or
a <a class="link" href="futures/packaged_task.html#class_packaged_task"><code class="computeroutput">packaged_task&lt;&gt;</code></a>. A <a class="link" href="futures/packaged_task.html#class_packaged_task"><code class="computeroutput">packaged_task&lt;&gt;</code></a> is
a callable object with <code class="computeroutput"><span class="keyword">void</span></code>
return that wraps a function or callable object returning the specified type.
When the <a class="link" href="futures/packaged_task.html#class_packaged_task"> <code class="computeroutput">packaged_task&lt;&gt;</code></a> is invoked, it invokes the
When the <a class="link" href="futures/packaged_task.html#class_packaged_task"><code class="computeroutput">packaged_task&lt;&gt;</code></a> 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: <span class="quote">&#8220;<span class="quote">How do
I return a value from a fiber?</span>&#8221;</span> Package the function you wish to run
as a <a class="link" href="futures/packaged_task.html#class_packaged_task"> <code class="computeroutput">packaged_task&lt;&gt;</code></a> and pass the packaged task to
as a <a class="link" href="futures/packaged_task.html#class_packaged_task"><code class="computeroutput">packaged_task&lt;&gt;</code></a> 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.
@@ -108,7 +108,7 @@ are
<span class="identifier">assert</span><span class="special">(</span><span class="identifier">fi</span><span class="special">.</span><span class="identifier">get</span><span class="special">()==</span><span class="number">42</span><span class="special">);</span>
</pre>
<p>
A <a class="link" href="futures/promise.html#class_promise"> <code class="computeroutput">promise&lt;&gt;</code></a> is a bit more low level: it just provides explicit
A <a class="link" href="futures/promise.html#class_promise"><code class="computeroutput">promise&lt;&gt;</code></a> 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.

View File

@@ -35,21 +35,21 @@
state</a>
</h6>
<p>
Behind a <a class="link" href="promise.html#class_promise"> <code class="computeroutput">promise&lt;&gt;</code></a> and its <a class="link" href="future.html#class_future"> <code class="computeroutput">future&lt;&gt;</code></a> lies
Behind a <a class="link" href="promise.html#class_promise"><code class="computeroutput">promise&lt;&gt;</code></a> and its <a class="link" href="future.html#class_future"><code class="computeroutput">future&lt;&gt;</code></a> lies
an unspecified object called their <span class="emphasis"><em>shared state</em></span>. The
shared state is what will actually hold the async result (or the exception).
</p>
<p>
The shared state is instantiated along with the <a class="link" href="promise.html#class_promise"> <code class="computeroutput">promise&lt;&gt;</code></a>.
The shared state is instantiated along with the <a class="link" href="promise.html#class_promise"><code class="computeroutput">promise&lt;&gt;</code></a>.
</p>
<p>
Aside from its originating <code class="computeroutput"><span class="identifier">promise</span><span class="special">&lt;&gt;</span></code>, a <a class="link" href="future.html#class_future"> <code class="computeroutput">future&lt;&gt;</code></a> holds
a unique reference to a particular shared state. However, multiple <a class="link" href="future.html#class_shared_future"> <code class="computeroutput">shared_future&lt;&gt;</code></a> instances
Aside from its originating <code class="computeroutput"><span class="identifier">promise</span><span class="special">&lt;&gt;</span></code>, a <a class="link" href="future.html#class_future"><code class="computeroutput">future&lt;&gt;</code></a> holds
a unique reference to a particular shared state. However, multiple <a class="link" href="future.html#class_shared_future"><code class="computeroutput">shared_future&lt;&gt;</code></a> instances
can reference the same underlying shared state.
</p>
<p>
As <a class="link" href="packaged_task.html#class_packaged_task"> <code class="computeroutput">packaged_task&lt;&gt;</code></a> and <a class="link" href="future.html#fibers_async"> <code class="computeroutput">fibers::async()</code></a> are
implemented using <a class="link" href="promise.html#class_promise"> <code class="computeroutput">promise&lt;&gt;</code></a>, discussions of shared state
As <a class="link" href="packaged_task.html#class_packaged_task"><code class="computeroutput">packaged_task&lt;&gt;</code></a> and <a class="link" href="future.html#fibers_async"><code class="computeroutput">fibers::async()</code></a> are
implemented using <a class="link" href="promise.html#class_promise"><code class="computeroutput">promise&lt;&gt;</code></a>, discussions of shared state
apply to them as well.
</p>
<a name="class_future_status"></a><h6>
@@ -58,7 +58,7 @@
<code class="computeroutput"><span class="identifier">future_status</span></code></a>
</h6>
<p>
Timed wait-operations ( <a class="link" href="future.html#future_wait_for"> <code class="computeroutput">future::wait_for()</code></a> and <a class="link" href="future.html#future_wait_until"> <code class="computeroutput">future::wait_until()</code></a>)
Timed wait-operations (<a class="link" href="future.html#future_wait_for"><code class="computeroutput">future::wait_for()</code></a> and <a class="link" href="future.html#future_wait_until"><code class="computeroutput">future::wait_until()</code></a>)
return the state of the future.
</p>
<pre class="programlisting"><span class="keyword">enum</span> <span class="keyword">class</span> <span class="identifier">future_status</span> <span class="special">{</span>
@@ -113,7 +113,7 @@
<p>
</p>
<p>
A <a class="link" href="future.html#class_future"> <code class="computeroutput">future&lt;&gt;</code></a> contains a <a class="link" href="future.html#shared_state">shared
A <a class="link" href="future.html#class_future"><code class="computeroutput">future&lt;&gt;</code></a> contains a <a class="link" href="future.html#shared_state">shared
state</a> which is not shared with any other future.
</p>
<pre class="programlisting"><span class="keyword">template</span><span class="special">&lt;</span> <span class="keyword">typename</span> <span class="identifier">R</span> <span class="special">&gt;</span>
@@ -218,20 +218,20 @@
</p>
<div class="orderedlist"><ol class="orderedlist" type="1">
<li class="listitem">
instantiate <a class="link" href="promise.html#class_promise"> <code class="computeroutput">promise&lt;&gt;</code></a>
instantiate <a class="link" href="promise.html#class_promise"><code class="computeroutput">promise&lt;&gt;</code></a>
</li>
<li class="listitem">
obtain its <code class="computeroutput"><span class="identifier">future</span><span class="special">&lt;&gt;</span></code>
via <a class="link" href="promise.html#promise_get_future"> <code class="computeroutput">promise::get_future()</code></a>
via <a class="link" href="promise.html#promise_get_future"><code class="computeroutput">promise::get_future()</code></a>
</li>
<li class="listitem">
launch <a class="link" href="../../fiber_mgmt/fiber.html#class_fiber"> <code class="computeroutput">fiber</code></a>, capturing <code class="computeroutput"><span class="identifier">promise</span><span class="special">&lt;&gt;</span></code>
launch <a class="link" href="../../fiber_mgmt/fiber.html#class_fiber"><code class="computeroutput">fiber</code></a>, capturing <code class="computeroutput"><span class="identifier">promise</span><span class="special">&lt;&gt;</span></code>
</li>
<li class="listitem">
destroy <code class="computeroutput"><span class="identifier">future</span><span class="special">&lt;&gt;</span></code>
</li>
<li class="listitem">
call <a class="link" href="promise.html#promise_set_value"> <code class="computeroutput">promise::set_value()</code></a>
call <a class="link" href="promise.html#promise_set_value"><code class="computeroutput">promise::set_value()</code></a>
</li>
</ol></div>
<p>
@@ -308,11 +308,11 @@
<dl>
<dt><span class="term">Effects:</span></dt>
<dd><p>
Move the state to a <a class="link" href="future.html#class_shared_future"> <code class="computeroutput">shared_future&lt;&gt;</code></a>.
Move the state to a <a class="link" href="future.html#class_shared_future"><code class="computeroutput">shared_future&lt;&gt;</code></a>.
</p></dd>
<dt><span class="term">Returns:</span></dt>
<dd><p>
a <a class="link" href="future.html#class_shared_future"> <code class="computeroutput">shared_future&lt;&gt;</code></a> containing the <a class="link" href="future.html#shared_state">shared
a <a class="link" href="future.html#class_shared_future"><code class="computeroutput">shared_future&lt;&gt;</code></a> containing the <a class="link" href="future.html#shared_state">shared
state</a> formerly belonging to <code class="computeroutput"><span class="special">*</span><span class="keyword">this</span></code>.
</p></dd>
<dt><span class="term">Postcondition:</span></dt>
@@ -350,9 +350,9 @@
</p></dd>
<dt><span class="term">Returns:</span></dt>
<dd><p>
Waits until <a class="link" href="promise.html#promise_set_value"> <code class="computeroutput">promise::set_value()</code></a> or <a class="link" href="promise.html#promise_set_exception"> <code class="computeroutput">promise::set_exception()</code></a> is
called. If <a class="link" href="promise.html#promise_set_value"> <code class="computeroutput">promise::set_value()</code></a> is called, returns
the value. If <a class="link" href="promise.html#promise_set_exception"> <code class="computeroutput">promise::set_exception()</code></a> is called,
Waits until <a class="link" href="promise.html#promise_set_value"><code class="computeroutput">promise::set_value()</code></a> or <a class="link" href="promise.html#promise_set_exception"><code class="computeroutput">promise::set_exception()</code></a> is
called. If <a class="link" href="promise.html#promise_set_value"><code class="computeroutput">promise::set_value()</code></a> is called, returns
the value. If <a class="link" href="promise.html#promise_set_exception"><code class="computeroutput">promise::set_exception()</code></a> is called,
throws the indicated exception.
</p></dd>
<dt><span class="term">Postcondition:</span></dt>
@@ -364,7 +364,6 @@
<dd><p>
<code class="computeroutput"><span class="identifier">future_error</span></code> with
error condition <code class="computeroutput"><span class="identifier">future_errc</span><span class="special">::</span><span class="identifier">no_state</span></code>,
<code class="computeroutput"><span class="identifier">fiber_interrupted</span></code>,
<code class="computeroutput"><span class="identifier">future_errc</span><span class="special">::</span><span class="identifier">broken_promise</span></code>. Any exception passed
to <code class="computeroutput"><span class="identifier">promise</span><span class="special">::</span><span class="identifier">set_exception</span><span class="special">()</span></code>.
</p></dd>
@@ -392,7 +391,7 @@
</p></dd>
<dt><span class="term">Returns:</span></dt>
<dd><p>
Waits until <a class="link" href="promise.html#promise_set_value"> <code class="computeroutput">promise::set_value()</code></a> or <a class="link" href="promise.html#promise_set_exception"> <code class="computeroutput">promise::set_exception()</code></a> is
Waits until <a class="link" href="promise.html#promise_set_value"><code class="computeroutput">promise::set_value()</code></a> or <a class="link" href="promise.html#promise_set_exception"><code class="computeroutput">promise::set_exception()</code></a> is
called. If <code class="computeroutput"><span class="identifier">set_value</span><span class="special">()</span></code> is called, returns a default-constructed
<code class="computeroutput"><span class="identifier">std</span><span class="special">::</span><span class="identifier">exception_ptr</span></code>. If <code class="computeroutput"><span class="identifier">set_exception</span><span class="special">()</span></code>
is called, returns the passed <code class="computeroutput"><span class="identifier">std</span><span class="special">::</span><span class="identifier">exception_ptr</span></code>.
@@ -400,13 +399,12 @@
<dt><span class="term">Throws:</span></dt>
<dd><p>
<code class="computeroutput"><span class="identifier">future_error</span></code> with
error condition <code class="computeroutput"><span class="identifier">future_errc</span><span class="special">::</span><span class="identifier">no_state</span></code>
or <code class="computeroutput"><span class="identifier">fiber_interrupted</span></code>.
error condition <code class="computeroutput"><span class="identifier">future_errc</span><span class="special">::</span><span class="identifier">no_state</span></code>.
</p></dd>
<dt><span class="term">Note:</span></dt>
<dd><p>
<code class="computeroutput"><span class="identifier">get_exception_ptr</span><span class="special">()</span></code> does <span class="emphasis"><em>not</em></span> invalidate
the <code class="computeroutput">future</code>. After calling <code class="computeroutput"><span class="identifier">get_exception_ptr</span><span class="special">()</span></code>, you may still call <a class="link" href="future.html#future_get"> <code class="computeroutput">future::get()</code></a>.
the <code class="computeroutput">future</code>. After calling <code class="computeroutput"><span class="identifier">get_exception_ptr</span><span class="special">()</span></code>, you may still call <a class="link" href="future.html#future_get"><code class="computeroutput">future::get()</code></a>.
</p></dd>
</dl>
</div>
@@ -426,14 +424,13 @@
<dl>
<dt><span class="term">Effects:</span></dt>
<dd><p>
Waits until <a class="link" href="promise.html#promise_set_value"> <code class="computeroutput">promise::set_value()</code></a> or <a class="link" href="promise.html#promise_set_exception"> <code class="computeroutput">promise::set_exception()</code></a> is
Waits until <a class="link" href="promise.html#promise_set_value"><code class="computeroutput">promise::set_value()</code></a> or <a class="link" href="promise.html#promise_set_exception"><code class="computeroutput">promise::set_exception()</code></a> is
called.
</p></dd>
<dt><span class="term">Throws:</span></dt>
<dd><p>
<code class="computeroutput"><span class="identifier">future_error</span></code> with
error condition <code class="computeroutput"><span class="identifier">future_errc</span><span class="special">::</span><span class="identifier">no_state</span></code>
or <code class="computeroutput"><span class="identifier">fiber_interrupted</span></code>.
error condition <code class="computeroutput"><span class="identifier">future_errc</span><span class="special">::</span><span class="identifier">no_state</span></code>.
</p></dd>
</dl>
</div>
@@ -455,7 +452,7 @@
<dl>
<dt><span class="term">Effects:</span></dt>
<dd><p>
Waits until <a class="link" href="promise.html#promise_set_value"> <code class="computeroutput">promise::set_value()</code></a> or <a class="link" href="promise.html#promise_set_exception"> <code class="computeroutput">promise::set_exception()</code></a> is
Waits until <a class="link" href="promise.html#promise_set_value"><code class="computeroutput">promise::set_value()</code></a> or <a class="link" href="promise.html#promise_set_exception"><code class="computeroutput">promise::set_exception()</code></a> is
called, or <code class="computeroutput"><span class="identifier">timeout_duration</span></code>
has passed.
</p></dd>
@@ -468,7 +465,6 @@
<dd><p>
<code class="computeroutput"><span class="identifier">future_error</span></code> with
error condition <code class="computeroutput"><span class="identifier">future_errc</span><span class="special">::</span><span class="identifier">no_state</span></code>
or <code class="computeroutput"><span class="identifier">fiber_interrupted</span></code>
or timeout-related exceptions.
</p></dd>
</dl>
@@ -491,7 +487,7 @@
<dl>
<dt><span class="term">Effects:</span></dt>
<dd><p>
Waits until <a class="link" href="promise.html#promise_set_value"> <code class="computeroutput">promise::set_value()</code></a> or <a class="link" href="promise.html#promise_set_exception"> <code class="computeroutput">promise::set_exception()</code></a> is
Waits until <a class="link" href="promise.html#promise_set_value"><code class="computeroutput">promise::set_value()</code></a> or <a class="link" href="promise.html#promise_set_exception"><code class="computeroutput">promise::set_exception()</code></a> is
called, or <code class="computeroutput"><span class="identifier">timeout_time</span></code>
has passed.
</p></dd>
@@ -504,7 +500,6 @@
<dd><p>
<code class="computeroutput"><span class="identifier">future_error</span></code> with
error condition <code class="computeroutput"><span class="identifier">future_errc</span><span class="special">::</span><span class="identifier">no_state</span></code>
or <code class="computeroutput"><span class="identifier">fiber_interrupted</span></code>
or timeout-related exceptions.
</p></dd>
</dl>
@@ -520,8 +515,8 @@
<p>
</p>
<p>
A <a class="link" href="future.html#class_shared_future"> <code class="computeroutput">shared_future&lt;&gt;</code></a> contains a <a class="link" href="future.html#shared_state">shared
state</a> which might be shared with other <a class="link" href="future.html#class_shared_future"> <code class="computeroutput">shared_future&lt;&gt;</code></a> instances.
A <a class="link" href="future.html#class_shared_future"><code class="computeroutput">shared_future&lt;&gt;</code></a> contains a <a class="link" href="future.html#shared_state">shared
state</a> which might be shared with other <a class="link" href="future.html#class_shared_future"><code class="computeroutput">shared_future&lt;&gt;</code></a> instances.
</p>
<pre class="programlisting"><span class="keyword">template</span><span class="special">&lt;</span> <span class="keyword">typename</span> <span class="identifier">R</span> <span class="special">&gt;</span>
<span class="keyword">class</span> <span class="identifier">shared_future</span> <span class="special">{</span>
@@ -726,9 +721,9 @@
</p></dd>
<dt><span class="term">Returns:</span></dt>
<dd><p>
Waits until <a class="link" href="promise.html#promise_set_value"> <code class="computeroutput">promise::set_value()</code></a> or <a class="link" href="promise.html#promise_set_exception"> <code class="computeroutput">promise::set_exception()</code></a> is
called. If <a class="link" href="promise.html#promise_set_value"> <code class="computeroutput">promise::set_value()</code></a> is called, returns
the value. If <a class="link" href="promise.html#promise_set_exception"> <code class="computeroutput">promise::set_exception()</code></a> is called,
Waits until <a class="link" href="promise.html#promise_set_value"><code class="computeroutput">promise::set_value()</code></a> or <a class="link" href="promise.html#promise_set_exception"><code class="computeroutput">promise::set_exception()</code></a> is
called. If <a class="link" href="promise.html#promise_set_value"><code class="computeroutput">promise::set_value()</code></a> is called, returns
the value. If <a class="link" href="promise.html#promise_set_exception"><code class="computeroutput">promise::set_exception()</code></a> is called,
throws the indicated exception.
</p></dd>
<dt><span class="term">Postcondition:</span></dt>
@@ -740,7 +735,6 @@
<dd><p>
<code class="computeroutput"><span class="identifier">future_error</span></code> with
error condition <code class="computeroutput"><span class="identifier">future_errc</span><span class="special">::</span><span class="identifier">no_state</span></code>,
<code class="computeroutput"><span class="identifier">fiber_interrupted</span></code>,
<code class="computeroutput"><span class="identifier">future_errc</span><span class="special">::</span><span class="identifier">broken_promise</span></code>. Any exception passed
to <code class="computeroutput"><span class="identifier">promise</span><span class="special">::</span><span class="identifier">set_exception</span><span class="special">()</span></code>.
</p></dd>
@@ -768,7 +762,7 @@
</p></dd>
<dt><span class="term">Returns:</span></dt>
<dd><p>
Waits until <a class="link" href="promise.html#promise_set_value"> <code class="computeroutput">promise::set_value()</code></a> or <a class="link" href="promise.html#promise_set_exception"> <code class="computeroutput">promise::set_exception()</code></a> is
Waits until <a class="link" href="promise.html#promise_set_value"><code class="computeroutput">promise::set_value()</code></a> or <a class="link" href="promise.html#promise_set_exception"><code class="computeroutput">promise::set_exception()</code></a> is
called. If <code class="computeroutput"><span class="identifier">set_value</span><span class="special">()</span></code> is called, returns a default-constructed
<code class="computeroutput"><span class="identifier">std</span><span class="special">::</span><span class="identifier">exception_ptr</span></code>. If <code class="computeroutput"><span class="identifier">set_exception</span><span class="special">()</span></code>
is called, returns the passed <code class="computeroutput"><span class="identifier">std</span><span class="special">::</span><span class="identifier">exception_ptr</span></code>.
@@ -776,13 +770,12 @@
<dt><span class="term">Throws:</span></dt>
<dd><p>
<code class="computeroutput"><span class="identifier">future_error</span></code> with
error condition <code class="computeroutput"><span class="identifier">future_errc</span><span class="special">::</span><span class="identifier">no_state</span></code>
or <code class="computeroutput"><span class="identifier">fiber_interrupted</span></code>.
error condition <code class="computeroutput"><span class="identifier">future_errc</span><span class="special">::</span><span class="identifier">no_state</span></code>.
</p></dd>
<dt><span class="term">Note:</span></dt>
<dd><p>
<code class="computeroutput"><span class="identifier">get_exception_ptr</span><span class="special">()</span></code> does <span class="emphasis"><em>not</em></span> invalidate
the <code class="computeroutput">shared_future</code>. After calling <code class="computeroutput"><span class="identifier">get_exception_ptr</span><span class="special">()</span></code>, you may still call <a class="link" href="future.html#shared_future_get"> <code class="computeroutput">shared_future::get()</code></a>.
the <code class="computeroutput">shared_future</code>. After calling <code class="computeroutput"><span class="identifier">get_exception_ptr</span><span class="special">()</span></code>, you may still call <a class="link" href="future.html#shared_future_get"><code class="computeroutput">shared_future::get()</code></a>.
</p></dd>
</dl>
</div>
@@ -803,14 +796,13 @@
<dl>
<dt><span class="term">Effects:</span></dt>
<dd><p>
Waits until <a class="link" href="promise.html#promise_set_value"> <code class="computeroutput">promise::set_value()</code></a> or <a class="link" href="promise.html#promise_set_exception"> <code class="computeroutput">promise::set_exception()</code></a> is
Waits until <a class="link" href="promise.html#promise_set_value"><code class="computeroutput">promise::set_value()</code></a> or <a class="link" href="promise.html#promise_set_exception"><code class="computeroutput">promise::set_exception()</code></a> is
called.
</p></dd>
<dt><span class="term">Throws:</span></dt>
<dd><p>
<code class="computeroutput"><span class="identifier">future_error</span></code> with
error condition <code class="computeroutput"><span class="identifier">future_errc</span><span class="special">::</span><span class="identifier">no_state</span></code>
or <code class="computeroutput"><span class="identifier">fiber_interrupted</span></code>.
error condition <code class="computeroutput"><span class="identifier">future_errc</span><span class="special">::</span><span class="identifier">no_state</span></code>.
</p></dd>
</dl>
</div>
@@ -832,7 +824,7 @@
<dl>
<dt><span class="term">Effects:</span></dt>
<dd><p>
Waits until <a class="link" href="promise.html#promise_set_value"> <code class="computeroutput">promise::set_value()</code></a> or <a class="link" href="promise.html#promise_set_exception"> <code class="computeroutput">promise::set_exception()</code></a> is
Waits until <a class="link" href="promise.html#promise_set_value"><code class="computeroutput">promise::set_value()</code></a> or <a class="link" href="promise.html#promise_set_exception"><code class="computeroutput">promise::set_exception()</code></a> is
called, or <code class="computeroutput"><span class="identifier">timeout_duration</span></code>
has passed.
</p></dd>
@@ -845,7 +837,6 @@
<dd><p>
<code class="computeroutput"><span class="identifier">future_error</span></code> with
error condition <code class="computeroutput"><span class="identifier">future_errc</span><span class="special">::</span><span class="identifier">no_state</span></code>
or <code class="computeroutput"><span class="identifier">fiber_interrupted</span></code>
or timeout-related exceptions.
</p></dd>
</dl>
@@ -868,7 +859,7 @@
<dl>
<dt><span class="term">Effects:</span></dt>
<dd><p>
Waits until <a class="link" href="promise.html#promise_set_value"> <code class="computeroutput">promise::set_value()</code></a> or <a class="link" href="promise.html#promise_set_exception"> <code class="computeroutput">promise::set_exception()</code></a> is
Waits until <a class="link" href="promise.html#promise_set_value"><code class="computeroutput">promise::set_value()</code></a> or <a class="link" href="promise.html#promise_set_exception"><code class="computeroutput">promise::set_exception()</code></a> is
called, or <code class="computeroutput"><span class="identifier">timeout_time</span></code>
has passed.
</p></dd>
@@ -881,7 +872,6 @@
<dd><p>
<code class="computeroutput"><span class="identifier">future_error</span></code> with
error condition <code class="computeroutput"><span class="identifier">future_errc</span><span class="special">::</span><span class="identifier">no_state</span></code>
or <code class="computeroutput"><span class="identifier">fiber_interrupted</span></code>
or timeout-related exceptions.
</p></dd>
</dl>
@@ -905,6 +895,14 @@
<span class="special">&gt;</span>
<span class="identifier">async</span><span class="special">(</span> <span class="identifier">Function</span> <span class="special">&amp;&amp;</span> <span class="identifier">fn</span><span class="special">,</span> <span class="identifier">Args</span> <span class="special">&amp;&amp;</span> <span class="special">...</span> <span class="identifier">args</span><span class="special">);</span>
<span class="keyword">template</span><span class="special">&lt;</span> <span class="keyword">class</span> <span class="identifier">Function</span><span class="special">,</span> <span class="keyword">class</span> <span class="special">...</span> <span class="identifier">Args</span> <span class="special">&gt;</span>
<span class="identifier">future</span><span class="special">&lt;</span>
<span class="identifier">std</span><span class="special">::</span><span class="identifier">result_of_t</span><span class="special">&lt;</span>
<span class="identifier">std</span><span class="special">::</span><span class="identifier">decay_t</span><span class="special">&lt;</span> <span class="identifier">Function</span> <span class="special">&gt;(</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">decay_t</span><span class="special">&lt;</span> <span class="identifier">Args</span> <span class="special">&gt;</span> <span class="special">...</span> <span class="special">)</span>
<span class="special">&gt;</span>
<span class="special">&gt;</span>
<span class="identifier">async</span><span class="special">(</span> <a class="link" href="../../fiber_mgmt.html#class_launch_policy"><code class="computeroutput"><span class="identifier">launch_policy</span></code></a> <span class="identifier">lpol</span><span class="special">,</span> <span class="identifier">Function</span> <span class="special">&amp;&amp;</span> <span class="identifier">fn</span><span class="special">,</span> <span class="identifier">Args</span> <span class="special">&amp;&amp;</span> <span class="special">...</span> <span class="identifier">args</span><span class="special">);</span>
<span class="keyword">template</span><span class="special">&lt;</span> <span class="keyword">typename</span> <a class="link" href="../../stack.html#stack_allocator_concept"><code class="computeroutput"><span class="identifier">StackAllocator</span></code></a><span class="special">,</span> <span class="keyword">class</span> <span class="identifier">Function</span><span class="special">,</span> <span class="keyword">class</span> <span class="special">...</span> <span class="identifier">Args</span> <span class="special">&gt;</span>
<span class="identifier">future</span><span class="special">&lt;</span>
<span class="identifier">std</span><span class="special">::</span><span class="identifier">result_of_t</span><span class="special">&lt;</span>
@@ -912,6 +910,15 @@
<span class="special">&gt;</span>
<span class="special">&gt;</span>
<span class="identifier">async</span><span class="special">(</span> <a href="http://en.cppreference.com/w/cpp/memory/allocator_arg_t" target="_top"><code class="computeroutput"><span class="identifier">std</span><span class="special">::</span><span class="identifier">allocator_arg_t</span></code></a><span class="special">,</span> <a class="link" href="../../stack.html#stack_allocator_concept"><code class="computeroutput"><span class="identifier">StackAllocator</span></code></a> <span class="identifier">salloc</span><span class="special">,</span> <span class="identifier">Function</span> <span class="special">&amp;&amp;</span> <span class="identifier">fn</span><span class="special">,</span> <span class="identifier">Args</span> <span class="special">&amp;&amp;</span> <span class="special">...</span> <span class="identifier">args</span><span class="special">);</span>
<span class="keyword">template</span><span class="special">&lt;</span> <span class="keyword">typename</span> <a class="link" href="../../stack.html#stack_allocator_concept"><code class="computeroutput"><span class="identifier">StackAllocator</span></code></a><span class="special">,</span> <span class="keyword">class</span> <span class="identifier">Function</span><span class="special">,</span> <span class="keyword">class</span> <span class="special">...</span> <span class="identifier">Args</span> <span class="special">&gt;</span>
<span class="identifier">future</span><span class="special">&lt;</span>
<span class="identifier">std</span><span class="special">::</span><span class="identifier">result_of_t</span><span class="special">&lt;</span>
<span class="identifier">std</span><span class="special">::</span><span class="identifier">decay_t</span><span class="special">&lt;</span> <span class="identifier">Function</span> <span class="special">&gt;(</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">decay_t</span><span class="special">&lt;</span> <span class="identifier">Args</span> <span class="special">&gt;</span> <span class="special">...</span> <span class="special">)</span>
<span class="special">&gt;</span>
<span class="special">&gt;</span>
<span class="identifier">async</span><span class="special">(</span> <a class="link" href="../../fiber_mgmt.html#class_launch_policy"><code class="computeroutput"><span class="identifier">launch_policy</span></code></a> <span class="identifier">lpol</span><span class="special">,</span> <a href="http://en.cppreference.com/w/cpp/memory/allocator_arg_t" target="_top"><code class="computeroutput"><span class="identifier">std</span><span class="special">::</span><span class="identifier">allocator_arg_t</span></code></a><span class="special">,</span> <a class="link" href="../../stack.html#stack_allocator_concept"><code class="computeroutput"><span class="identifier">StackAllocator</span></code></a> <span class="identifier">salloc</span><span class="special">,</span>
<span class="identifier">Function</span> <span class="special">&amp;&amp;</span> <span class="identifier">fn</span><span class="special">,</span> <span class="identifier">Args</span> <span class="special">&amp;&amp;</span> <span class="special">...</span> <span class="identifier">args</span><span class="special">);</span>
</pre>
<div class="variablelist">
<p class="title"><b></b></p>
@@ -919,7 +926,7 @@
<dt><span class="term">Effects:</span></dt>
<dd><p>
Executes <code class="computeroutput"><span class="identifier">fn</span></code> in a
<a class="link" href="../../fiber_mgmt/fiber.html#class_fiber"> <code class="computeroutput">fiber</code></a> and returns an associated <a class="link" href="future.html#class_future"> <code class="computeroutput">future&lt;&gt;</code></a>.
<a class="link" href="../../fiber_mgmt/fiber.html#class_fiber"><code class="computeroutput">fiber</code></a> and returns an associated <a class="link" href="future.html#class_future"><code class="computeroutput">future&lt;&gt;</code></a>.
</p></dd>
<dt><span class="term">Result:</span></dt>
<dd>
@@ -941,9 +948,15 @@
</p></dd>
<dt><span class="term">Notes:</span></dt>
<dd><p>
The overload accepting <a href="http://en.cppreference.com/w/cpp/memory/allocator_arg_t" target="_top"><code class="computeroutput"><span class="identifier">std</span><span class="special">::</span><span class="identifier">allocator_arg_t</span></code></a> uses the
The overloads accepting <a href="http://en.cppreference.com/w/cpp/memory/allocator_arg_t" target="_top"><code class="computeroutput"><span class="identifier">std</span><span class="special">::</span><span class="identifier">allocator_arg_t</span></code></a> use the
passed <a class="link" href="../../stack.html#stack_allocator_concept"><code class="computeroutput"><span class="identifier">StackAllocator</span></code></a>
when constructing the launched <code class="computeroutput"><span class="identifier">fiber</span></code>.
The overloads accepting <a class="link" href="../../fiber_mgmt.html#class_launch_policy"><code class="computeroutput">launch_policy</code></a> use the passed
<code class="computeroutput"><span class="identifier">launch_policy</span></code> when
constructing the launched <code class="computeroutput"><span class="identifier">fiber</span></code>.
The default <code class="computeroutput"><span class="identifier">launch_policy</span></code>
is <code class="computeroutput"><span class="identifier">post</span></code>, as for the
<code class="computeroutput"><span class="identifier">fiber</span></code> constructor.
</p></dd>
</dl>
</div>

View File

@@ -28,7 +28,7 @@
<code class="computeroutput"><span class="identifier">packaged_task</span><span class="special">&lt;&gt;</span></code></a>
</h4></div></div></div>
<p>
A <a class="link" href="packaged_task.html#class_packaged_task"> <code class="computeroutput">packaged_task&lt;&gt;</code></a> wraps a callable target that
A <a class="link" href="packaged_task.html#class_packaged_task"><code class="computeroutput">packaged_task&lt;&gt;</code></a> wraps a callable target that
returns a value so that the return value can be computed asynchronously.
</p>
<p>
@@ -40,22 +40,22 @@
the signature of the callable. Pass the callable to the <a class="link" href="packaged_task.html#packaged_task_packaged_task">constructor</a>.
</li>
<li class="listitem">
Call <a class="link" href="packaged_task.html#packaged_task_get_future"> <code class="computeroutput">packaged_task::get_future()</code></a> and capture
the returned <a class="link" href="future.html#class_future"> <code class="computeroutput">future&lt;&gt;</code></a> instance.
Call <a class="link" href="packaged_task.html#packaged_task_get_future"><code class="computeroutput">packaged_task::get_future()</code></a> and capture
the returned <a class="link" href="future.html#class_future"><code class="computeroutput">future&lt;&gt;</code></a> instance.
</li>
<li class="listitem">
Launch a <a class="link" href="../../fiber_mgmt/fiber.html#class_fiber"> <code class="computeroutput">fiber</code></a> to run the new <code class="computeroutput"><span class="identifier">packaged_task</span><span class="special">&lt;&gt;</span></code>, passing any arguments required
Launch a <a class="link" href="../../fiber_mgmt/fiber.html#class_fiber"><code class="computeroutput">fiber</code></a> to run the new <code class="computeroutput"><span class="identifier">packaged_task</span><span class="special">&lt;&gt;</span></code>, passing any arguments required
by the original callable.
</li>
<li class="listitem">
Call <a class="link" href="../../fiber_mgmt/fiber.html#fiber_detach"> <code class="computeroutput">fiber::detach()</code></a> on the newly-launched <code class="computeroutput"><span class="identifier">fiber</span></code>.
Call <a class="link" href="../../fiber_mgmt/fiber.html#fiber_detach"><code class="computeroutput">fiber::detach()</code></a> on the newly-launched <code class="computeroutput"><span class="identifier">fiber</span></code>.
</li>
<li class="listitem">
At some later point, retrieve the result from the <code class="computeroutput"><span class="identifier">future</span><span class="special">&lt;&gt;</span></code>.
</li>
</ol></div>
<p>
This is, in fact, pretty much what <a class="link" href="future.html#fibers_async"> <code class="computeroutput">fibers::async()</code></a>
This is, in fact, pretty much what <a class="link" href="future.html#fibers_async"><code class="computeroutput">fibers::async()</code></a>
encapsulates.
</p>
<pre class="programlisting"><span class="keyword">template</span><span class="special">&lt;</span> <span class="keyword">class</span> <span class="identifier">R</span><span class="special">,</span> <span class="keyword">typename</span> <span class="special">...</span> <span class="identifier">Args</span> <span class="special">&gt;</span>
@@ -191,7 +191,7 @@ encapsulates.
and abandons the <a class="link" href="future.html#shared_state">shared state</a>
if shared state is ready; otherwise stores <code class="computeroutput"><span class="identifier">future_error</span></code>
with error condition <code class="computeroutput"><span class="identifier">future_errc</span><span class="special">::</span><span class="identifier">broken_promise</span></code>
as if by <a class="link" href="promise.html#promise_set_exception"> <code class="computeroutput">promise::set_exception()</code></a>: the shared
as if by <a class="link" href="promise.html#promise_set_exception"><code class="computeroutput">promise::set_exception()</code></a>: the shared
state is set ready.
</p></dd>
</dl>
@@ -296,7 +296,7 @@ encapsulates.
<dl>
<dt><span class="term">Returns:</span></dt>
<dd><p>
A <a class="link" href="future.html#class_future"> <code class="computeroutput">future&lt;&gt;</code></a> with the same <a class="link" href="future.html#shared_state">shared
A <a class="link" href="future.html#class_future"><code class="computeroutput">future&lt;&gt;</code></a> with the same <a class="link" href="future.html#shared_state">shared
state</a>.
</p></dd>
<dt><span class="term">Throws:</span></dt>
@@ -326,9 +326,9 @@ encapsulates.
Invokes the stored callable target. Any exception thrown by the callable
target <code class="computeroutput"><span class="identifier">fn</span></code> is stored
in the <a class="link" href="future.html#shared_state">shared state</a> as if by
<a class="link" href="promise.html#promise_set_exception"> <code class="computeroutput">promise::set_exception()</code></a>. Otherwise, the value
<a class="link" href="promise.html#promise_set_exception"><code class="computeroutput">promise::set_exception()</code></a>. Otherwise, the value
returned by <code class="computeroutput"><span class="identifier">fn</span></code> is
stored in the shared state as if by <a class="link" href="promise.html#promise_set_value"> <code class="computeroutput">promise::set_value()</code></a>.
stored in the shared state as if by <a class="link" href="promise.html#promise_set_value"><code class="computeroutput">promise::set_value()</code></a>.
</p></dd>
<dt><span class="term">Throws:</span></dt>
<dd><p>

View File

@@ -28,8 +28,8 @@
<code class="computeroutput"><span class="identifier">promise</span><span class="special">&lt;&gt;</span></code></a>
</h4></div></div></div>
<p>
A <a class="link" href="promise.html#class_promise"> <code class="computeroutput">promise&lt;&gt;</code></a> provides a mechanism to store a value (or
exception) that can later be retrieved from the corresponding <a class="link" href="future.html#class_future"> <code class="computeroutput">future&lt;&gt;</code></a> object.
A <a class="link" href="promise.html#class_promise"><code class="computeroutput">promise&lt;&gt;</code></a> provides a mechanism to store a value (or
exception) that can later be retrieved from the corresponding <a class="link" href="future.html#class_future"><code class="computeroutput">future&lt;&gt;</code></a> object.
<code class="computeroutput"><span class="identifier">promise</span><span class="special">&lt;&gt;</span></code>
and <code class="computeroutput"><span class="identifier">future</span><span class="special">&lt;&gt;</span></code>
communicate via their underlying <a class="link" href="future.html#shared_state">shared state</a>.
@@ -153,7 +153,7 @@
and abandons the <a class="link" href="future.html#shared_state">shared state</a>
if shared state is ready; otherwise stores <code class="computeroutput"><span class="identifier">future_error</span></code>
with error condition <code class="computeroutput"><span class="identifier">future_errc</span><span class="special">::</span><span class="identifier">broken_promise</span></code>
as if by <a class="link" href="promise.html#promise_set_exception"> <code class="computeroutput">promise::set_exception()</code></a>: the shared
as if by <a class="link" href="promise.html#promise_set_exception"><code class="computeroutput">promise::set_exception()</code></a>: the shared
state is set ready.
</p></dd>
</dl>
@@ -231,7 +231,7 @@
<dl>
<dt><span class="term">Returns:</span></dt>
<dd><p>
A <a class="link" href="future.html#class_future"> <code class="computeroutput">future&lt;&gt;</code></a> with the same <a class="link" href="future.html#shared_state">shared
A <a class="link" href="future.html#class_future"><code class="computeroutput">future&lt;&gt;</code></a> with the same <a class="link" href="future.html#shared_state">shared
state</a>.
</p></dd>
<dt><span class="term">Throws:</span></dt>

View File

@@ -51,8 +51,8 @@
<span class="special">};</span>
</pre>
<p>
<a class="link" href="mutex_types.html#class_mutex"> <code class="computeroutput">mutex</code></a> provides an exclusive-ownership mutex. At most one fiber
can own the lock on a given instance of <a class="link" href="mutex_types.html#class_mutex"> <code class="computeroutput">mutex</code></a> at any time. Multiple
<a class="link" href="mutex_types.html#class_mutex"><code class="computeroutput">mutex</code></a> provides an exclusive-ownership mutex. At most one fiber
can own the lock on a given instance of <a class="link" href="mutex_types.html#class_mutex"><code class="computeroutput">mutex</code></a> at any time. Multiple
concurrent calls to <code class="computeroutput"><span class="identifier">lock</span><span class="special">()</span></code>, <code class="computeroutput"><span class="identifier">try_lock</span><span class="special">()</span></code> and <code class="computeroutput"><span class="identifier">unlock</span><span class="special">()</span></code> shall be permitted.
</p>
<p>
@@ -197,8 +197,8 @@
<span class="special">};</span>
</pre>
<p>
<a class="link" href="mutex_types.html#class_timed_mutex"> <code class="computeroutput">timed_mutex</code></a> provides an exclusive-ownership mutex. At most
one fiber can own the lock on a given instance of <a class="link" href="mutex_types.html#class_timed_mutex"> <code class="computeroutput">timed_mutex</code></a> at
<a class="link" href="mutex_types.html#class_timed_mutex"><code class="computeroutput">timed_mutex</code></a> provides an exclusive-ownership mutex. At most
one fiber can own the lock on a given instance of <a class="link" href="mutex_types.html#class_timed_mutex"><code class="computeroutput">timed_mutex</code></a> at
any time. Multiple concurrent calls to <code class="computeroutput"><span class="identifier">lock</span><span class="special">()</span></code>, <code class="computeroutput"><span class="identifier">try_lock</span><span class="special">()</span></code>, <code class="computeroutput"><span class="identifier">try_lock_until</span><span class="special">()</span></code>, <code class="computeroutput"><span class="identifier">try_lock_for</span><span class="special">()</span></code> and <code class="computeroutput"><span class="identifier">unlock</span><span class="special">()</span></code> shall be permitted.
</p>
<p>
@@ -336,7 +336,7 @@
<dd><p>
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 <a class="link" href="mutex_types.html#timed_mutex_try_lock"> <code class="computeroutput">timed_mutex::try_lock()</code></a>.
time has already passed, behaves as <a class="link" href="mutex_types.html#timed_mutex_try_lock"><code class="computeroutput">timed_mutex::try_lock()</code></a>.
</p></dd>
<dt><span class="term">Returns:</span></dt>
<dd><p>
@@ -381,7 +381,7 @@
<dd><p>
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 <a class="link" href="mutex_types.html#timed_mutex_try_lock"> <code class="computeroutput">timed_mutex::try_lock()</code></a>.
time has already passed, behaves as <a class="link" href="mutex_types.html#timed_mutex_try_lock"><code class="computeroutput">timed_mutex::try_lock()</code></a>.
</p></dd>
<dt><span class="term">Returns:</span></dt>
<dd><p>
@@ -428,10 +428,10 @@
<span class="special">};</span>
</pre>
<p>
<a class="link" href="mutex_types.html#class_recursive_mutex"> <code class="computeroutput">recursive_mutex</code></a> provides an exclusive-ownership recursive
mutex. At most one fiber can own the lock on a given instance of <a class="link" href="mutex_types.html#class_recursive_mutex"> <code class="computeroutput">recursive_mutex</code></a> at
<a class="link" href="mutex_types.html#class_recursive_mutex"><code class="computeroutput">recursive_mutex</code></a> provides an exclusive-ownership recursive
mutex. At most one fiber can own the lock on a given instance of <a class="link" href="mutex_types.html#class_recursive_mutex"><code class="computeroutput">recursive_mutex</code></a> at
any time. Multiple concurrent calls to <code class="computeroutput"><span class="identifier">lock</span><span class="special">()</span></code>, <code class="computeroutput"><span class="identifier">try_lock</span><span class="special">()</span></code> and <code class="computeroutput"><span class="identifier">unlock</span><span class="special">()</span></code> shall be permitted. A fiber that already
has exclusive ownership of a given <a class="link" href="mutex_types.html#class_recursive_mutex"> <code class="computeroutput">recursive_mutex</code></a> instance
has exclusive ownership of a given <a class="link" href="mutex_types.html#class_recursive_mutex"><code class="computeroutput">recursive_mutex</code></a> instance
can call <code class="computeroutput"><span class="identifier">lock</span><span class="special">()</span></code>
or <code class="computeroutput"><span class="identifier">try_lock</span><span class="special">()</span></code>
to acquire an additional level of ownership of the mutex. <code class="computeroutput"><span class="identifier">unlock</span><span class="special">()</span></code> must be called once for each level of ownership
@@ -458,7 +458,7 @@
</p></dd>
<dt><span class="term">Throws:</span></dt>
<dd><p>
<code class="computeroutput"><span class="identifier">fiber_interrupted</span></code>
Nothing
</p></dd>
</dl>
</div>
@@ -555,16 +555,16 @@
<span class="special">};</span>
</pre>
<p>
<a class="link" href="mutex_types.html#class_recursive_timed_mutex"> <code class="computeroutput">recursive_timed_mutex</code></a> provides an exclusive-ownership
<a class="link" href="mutex_types.html#class_recursive_timed_mutex"><code class="computeroutput">recursive_timed_mutex</code></a> provides an exclusive-ownership
recursive mutex. At most one fiber can own the lock on a given instance of
<a class="link" href="mutex_types.html#class_recursive_timed_mutex"> <code class="computeroutput">recursive_timed_mutex</code></a> at any time. Multiple concurrent
<a class="link" href="mutex_types.html#class_recursive_timed_mutex"><code class="computeroutput">recursive_timed_mutex</code></a> at any time. Multiple concurrent
calls to <code class="computeroutput"><span class="identifier">lock</span><span class="special">()</span></code>,
<code class="computeroutput"><span class="identifier">try_lock</span><span class="special">()</span></code>,
<code class="computeroutput"><span class="identifier">try_lock_for</span><span class="special">()</span></code>,
<code class="computeroutput"><span class="identifier">try_lock_until</span><span class="special">()</span></code>
and <code class="computeroutput"><span class="identifier">unlock</span><span class="special">()</span></code>
shall be permitted. A fiber that already has exclusive ownership of a given
<a class="link" href="mutex_types.html#class_recursive_timed_mutex"> <code class="computeroutput">recursive_timed_mutex</code></a> instance can call <code class="computeroutput"><span class="identifier">lock</span><span class="special">()</span></code>,
<a class="link" href="mutex_types.html#class_recursive_timed_mutex"><code class="computeroutput">recursive_timed_mutex</code></a> instance can call <code class="computeroutput"><span class="identifier">lock</span><span class="special">()</span></code>,
<code class="computeroutput"><span class="identifier">try_lock</span><span class="special">()</span></code>,
<code class="computeroutput"><span class="identifier">try_lock_for</span><span class="special">()</span></code>
or <code class="computeroutput"><span class="identifier">try_lock_until</span><span class="special">()</span></code>
@@ -592,7 +592,7 @@
</p></dd>
<dt><span class="term">Throws:</span></dt>
<dd><p>
<code class="computeroutput"><span class="identifier">fiber_interrupted</span></code>
Nothing
</p></dd>
</dl>
</div>
@@ -678,7 +678,7 @@
<dd><p>
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 <a class="link" href="mutex_types.html#recursive_timed_mutex_try_lock"> <code class="computeroutput">recursive_timed_mutex::try_lock()</code></a>.
time has already passed, behaves as <a class="link" href="mutex_types.html#recursive_timed_mutex_try_lock"><code class="computeroutput">recursive_timed_mutex::try_lock()</code></a>.
</p></dd>
<dt><span class="term">Returns:</span></dt>
<dd><p>
@@ -712,7 +712,7 @@
<dd><p>
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 <a class="link" href="mutex_types.html#recursive_timed_mutex_try_lock"> <code class="computeroutput">recursive_timed_mutex::try_lock()</code></a>.
time has already passed, behaves as <a class="link" href="mutex_types.html#recursive_timed_mutex_try_lock"><code class="computeroutput">recursive_timed_mutex::try_lock()</code></a>.
</p></dd>
<dt><span class="term">Returns:</span></dt>
<dd><p>

View File

@@ -106,8 +106,8 @@
<p>
The trouble with this tactic is that it would serialize all the task functions.
The runtime makes a single pass through <code class="computeroutput"><span class="identifier">functions</span></code>,
calling <a class="link" href="../../synchronization/futures/future.html#fibers_async"> <code class="computeroutput">fibers::async()</code></a> for each and then immediately calling
<a class="link" href="../../synchronization/futures/future.html#future_get"> <code class="computeroutput">future::get()</code></a> on its returned <code class="computeroutput"><span class="identifier">future</span><span class="special">&lt;&gt;</span></code>. That blocks the implicit loop.
calling <a class="link" href="../../synchronization/futures/future.html#fibers_async"><code class="computeroutput">fibers::async()</code></a> for each and then immediately calling
<a class="link" href="../../synchronization/futures/future.html#future_get"><code class="computeroutput">future::get()</code></a> on its returned <code class="computeroutput"><span class="identifier">future</span><span class="special">&lt;&gt;</span></code>. That blocks the implicit loop.
The above is almost equivalent to writing:
</p>
<pre class="programlisting"><span class="keyword">return</span> <span class="identifier">Result</span><span class="special">{</span> <span class="identifier">functions</span><span class="special">()...</span> <span class="special">};</span>

View File

@@ -40,7 +40,7 @@
available?
</p>
<p>
Fortunately we can present both APIs. Let's define <code class="computeroutput"><span class="identifier">wait_all_values_source</span><span class="special">()</span></code> to return <code class="computeroutput"><span class="identifier">shared_ptr</span><span class="special">&lt;</span><span class="identifier">unbounded_channel</span><span class="special">&lt;</span><span class="identifier">T</span><span class="special">&gt;&gt;</span></code>.<sup>[<a name="fiber.when_any.when_all_functionality.when_all__return_values.f0" href="#ftn.fiber.when_any.when_all_functionality.when_all__return_values.f0" class="footnote">7</a>]</sup>
Fortunately we can present both APIs. Let's define <code class="computeroutput"><span class="identifier">wait_all_values_source</span><span class="special">()</span></code> to return <code class="computeroutput"><span class="identifier">shared_ptr</span><span class="special">&lt;</span><span class="identifier">unbounded_channel</span><span class="special">&lt;</span><span class="identifier">T</span><span class="special">&gt;&gt;</span></code>.<sup>[<a name="fiber.when_any.when_all_functionality.when_all__return_values.f0" href="#ftn.fiber.when_any.when_all_functionality.when_all__return_values.f0" class="footnote">6</a>]</sup>
</p>
<p>
<a name="wait_all_values"></a>Given <code class="computeroutput"><span class="identifier">wait_all_values_source</span><span class="special">()</span></code>, it's straightforward to implement <code class="computeroutput"><span class="identifier">wait_all_values</span><span class="special">()</span></code>:
@@ -86,9 +86,9 @@
</p>
<p>
As you can see from the loop in <code class="computeroutput"><span class="identifier">wait_all_values</span><span class="special">()</span></code>, instead of requiring its caller to count
values, we define <code class="computeroutput"><span class="identifier">wait_all_values_source</span><span class="special">()</span></code> to <a class="link" href="../../synchronization/channels.html#unbounded_channel_close"> <code class="computeroutput">unbounded_channel::close()</code></a> the
values, we define <code class="computeroutput"><span class="identifier">wait_all_values_source</span><span class="special">()</span></code> to <a class="link" href="../../synchronization/channels.html#unbounded_channel_close"><code class="computeroutput">unbounded_channel::close()</code></a> the
channel when done. But how do we do that? Each producer fiber is independent.
It has no idea whether it is the last one to <a class="link" href="../../synchronization/channels.html#unbounded_channel_push"> <code class="computeroutput">unbounded_channel::push()</code></a> a
It has no idea whether it is the last one to <a class="link" href="../../synchronization/channels.html#unbounded_channel_push"><code class="computeroutput">unbounded_channel::push()</code></a> a
value.
</p>
<p>
@@ -203,9 +203,9 @@
</p>
<div class="footnotes">
<br><hr width="100" align="left">
<div class="footnote"><p><sup>[<a name="ftn.fiber.when_any.when_all_functionality.when_all__return_values.f0" href="#fiber.when_any.when_all_functionality.when_all__return_values.f0" class="para">7</a>] </sup>
We could have used either <a class="link" href="../../synchronization/channels.html#class_bounded_channel"> <code class="computeroutput">bounded_channel&lt;&gt;</code></a> or
<a class="link" href="../../synchronization/channels.html#class_unbounded_channel"> <code class="computeroutput">unbounded_channel&lt;&gt;</code></a>. We chose <code class="computeroutput"><span class="identifier">unbounded_channel</span><span class="special">&lt;&gt;</span></code>
<div class="footnote"><p><sup>[<a name="ftn.fiber.when_any.when_all_functionality.when_all__return_values.f0" href="#fiber.when_any.when_all_functionality.when_all__return_values.f0" class="para">6</a>] </sup>
We could have used either <a class="link" href="../../synchronization/channels.html#class_bounded_channel"><code class="computeroutput">bounded_channel&lt;&gt;</code></a> or
<a class="link" href="../../synchronization/channels.html#class_unbounded_channel"><code class="computeroutput">unbounded_channel&lt;&gt;</code></a>. We chose <code class="computeroutput"><span class="identifier">unbounded_channel</span><span class="special">&lt;&gt;</span></code>
on the assumption that its simpler semantics imply a cheaper implementation.
</p></div>
</div>

View File

@@ -31,8 +31,8 @@
For the case in which we must wait for <span class="emphasis"><em>all</em></span> task functions
to complete &#8212; but we don't need results (or expect exceptions) from any of
them &#8212; we can write <code class="computeroutput"><span class="identifier">wait_all_simple</span><span class="special">()</span></code> that looks remarkably like <a class="link" href="../when_any/when_any__simple_completion.html#wait_first_simple"><code class="computeroutput"><span class="identifier">wait_first_simple</span><span class="special">()</span></code></a>.
The difference is that instead of our <a class="link" href="../when_any/when_any__simple_completion.html#wait_done"><code class="computeroutput"><span class="identifier">Done</span></code></a> class, we instantiate a <a class="link" href="../../synchronization/barriers.html#class_barrier"> <code class="computeroutput">barrier</code></a> and
call its <a class="link" href="../../synchronization/barriers.html#barrier_wait"> <code class="computeroutput">barrier::wait()</code></a>.
The difference is that instead of our <a class="link" href="../when_any/when_any__simple_completion.html#wait_done"><code class="computeroutput"><span class="identifier">Done</span></code></a> class, we instantiate a <a class="link" href="../../synchronization/barriers.html#class_barrier"><code class="computeroutput">barrier</code></a> and
call its <a class="link" href="../../synchronization/barriers.html#barrier_wait"><code class="computeroutput">barrier::wait()</code></a>.
</p>
<p>
We initialize the <code class="computeroutput"><span class="identifier">barrier</span></code>

View File

@@ -35,7 +35,7 @@
instead of plain <code class="computeroutput"><span class="identifier">T</span></code>.
</p>
<p>
<a name="wait_all_until_error"></a><code class="computeroutput"><span class="identifier">wait_all_until_error</span><span class="special">()</span></code> pops that <code class="computeroutput"><span class="identifier">future</span><span class="special">&lt;</span> <span class="identifier">T</span> <span class="special">&gt;</span></code> and calls its <a class="link" href="../../synchronization/futures/future.html#future_get"> <code class="computeroutput">future::get()</code></a>:
<a name="wait_all_until_error"></a><code class="computeroutput"><span class="identifier">wait_all_until_error</span><span class="special">()</span></code> pops that <code class="computeroutput"><span class="identifier">future</span><span class="special">&lt;</span> <span class="identifier">T</span> <span class="special">&gt;</span></code> and calls its <a class="link" href="../../synchronization/futures/future.html#future_get"><code class="computeroutput">future::get()</code></a>:
</p>
<p>
</p>

View File

@@ -31,13 +31,12 @@
Certain topics in C++ can arouse strong passions, and exceptions are no
exception. We cannot resist mentioning &#8212; for purely informational purposes
&#8212; that when you need only the <span class="emphasis"><em>first</em></span> result from some
number of concurrently-running fibers, it would be possible to pass a <code class="computeroutput">shared_ptr&lt;
<a class="link" href="../../synchronization/futures/promise.html#class_promise"> <code class="computeroutput">promise&lt;&gt;</code></a>&gt;</code> to the participating fibers, then cause
the initiating fiber to call <a class="link" href="../../synchronization/futures/future.html#future_get"> <code class="computeroutput">future::get()</code></a> on its <a class="link" href="../../synchronization/futures/future.html#class_future"> <code class="computeroutput">future&lt;&gt;</code></a>.
The first fiber to call <a class="link" href="../../synchronization/futures/promise.html#promise_set_value"> <code class="computeroutput">promise::set_value()</code></a> on that shared
<code class="computeroutput"><span class="identifier">promise</span></code> will succeed; subsequent
<code class="computeroutput"><span class="identifier">set_value</span><span class="special">()</span></code>
calls on the same <code class="computeroutput"><span class="identifier">promise</span></code>
number of concurrently-running fibers, it would be possible to pass a
<code class="literal">shared_ptr&lt;<a class="link" href="../../synchronization/futures/promise.html#class_promise"><code class="computeroutput">promise&lt;&gt;</code></a>&gt;</code> to the
participating fibers, then cause the initiating fiber to call <a class="link" href="../../synchronization/futures/future.html#future_get"><code class="computeroutput">future::get()</code></a> on
its <a class="link" href="../../synchronization/futures/future.html#class_future"><code class="computeroutput">future&lt;&gt;</code></a>. The first fiber to call <a class="link" href="../../synchronization/futures/promise.html#promise_set_value"><code class="computeroutput">promise::set_value()</code></a> on
that shared <code class="computeroutput"><span class="identifier">promise</span></code> will
succeed; subsequent <code class="computeroutput"><span class="identifier">set_value</span><span class="special">()</span></code> calls on the same <code class="computeroutput"><span class="identifier">promise</span></code>
instance will throw <code class="computeroutput"><span class="identifier">future_error</span></code>.
</p>
<p>

View File

@@ -35,15 +35,15 @@
</p>
<p>
Let's at least ensure that such an exception would propagate to the fiber
awaiting the first result. We can use <a class="link" href="../../synchronization/futures/future.html#class_future"> <code class="computeroutput">future&lt;&gt;</code></a> to transport
either a return value or an exception. Therefore, we will change <a class="link" href="when_any__return_value.html#wait_first_value"><code class="computeroutput"><span class="identifier">wait_first_value</span><span class="special">()</span></code></a>'s <a class="link" href="../../synchronization/channels.html#class_unbounded_channel"> <code class="computeroutput">unbounded_channel&lt;&gt;</code></a> to
awaiting the first result. We can use <a class="link" href="../../synchronization/futures/future.html#class_future"><code class="computeroutput">future&lt;&gt;</code></a> to transport
either a return value or an exception. Therefore, we will change <a class="link" href="when_any__return_value.html#wait_first_value"><code class="computeroutput"><span class="identifier">wait_first_value</span><span class="special">()</span></code></a>'s <a class="link" href="../../synchronization/channels.html#class_unbounded_channel"><code class="computeroutput">unbounded_channel&lt;&gt;</code></a> to
hold <code class="computeroutput"><span class="identifier">future</span><span class="special">&lt;</span>
<span class="identifier">T</span> <span class="special">&gt;</span></code>
items instead of simply <code class="computeroutput"><span class="identifier">T</span></code>.
</p>
<p>
Once we have a <code class="computeroutput"><span class="identifier">future</span><span class="special">&lt;&gt;</span></code>
in hand, all we need do is call <a class="link" href="../../synchronization/futures/future.html#future_get"> <code class="computeroutput">future::get()</code></a>, which will either
in hand, all we need do is call <a class="link" href="../../synchronization/futures/future.html#future_get"><code class="computeroutput">future::get()</code></a>, which will either
return the value or rethrow the exception.
</p>
<p>
@@ -75,10 +75,10 @@
</p>
<p>
So far so good &#8212; but there's a timing issue. How should we obtain the <code class="computeroutput"><span class="identifier">future</span><span class="special">&lt;&gt;</span></code>
to <a class="link" href="../../synchronization/channels.html#unbounded_channel_push"> <code class="computeroutput">unbounded_channel::push()</code></a> on the channel?
to <a class="link" href="../../synchronization/channels.html#unbounded_channel_push"><code class="computeroutput">unbounded_channel::push()</code></a> on the channel?
</p>
<p>
We could call <a class="link" href="../../synchronization/futures/future.html#fibers_async"> <code class="computeroutput">fibers::async()</code></a>. That would certainly produce
We could call <a class="link" href="../../synchronization/futures/future.html#fibers_async"><code class="computeroutput">fibers::async()</code></a>. That would certainly produce
a <code class="computeroutput"><span class="identifier">future</span><span class="special">&lt;&gt;</span></code>
for the task function. The trouble is that it would return too quickly!
We only want <code class="computeroutput"><span class="identifier">future</span><span class="special">&lt;&gt;</span></code>
@@ -90,19 +90,19 @@
completes most quickly.
</p>
<p>
Calling <a class="link" href="../../synchronization/futures/future.html#future_get"> <code class="computeroutput">future::get()</code></a> on the future returned by <code class="computeroutput"><span class="identifier">async</span><span class="special">()</span></code>
Calling <a class="link" href="../../synchronization/futures/future.html#future_get"><code class="computeroutput">future::get()</code></a> on the future returned by <code class="computeroutput"><span class="identifier">async</span><span class="special">()</span></code>
wouldn't be right. You can only call <code class="computeroutput"><span class="identifier">get</span><span class="special">()</span></code> once per <code class="computeroutput"><span class="identifier">future</span><span class="special">&lt;&gt;</span></code> instance! And if there were an
exception, it would be rethrown inside the helper fiber at the producer
end of the channel, rather than propagated to the consumer end.
</p>
<p>
We could call <a class="link" href="../../synchronization/futures/future.html#future_wait"> <code class="computeroutput">future::wait()</code></a>. That would block the helper fiber
We could call <a class="link" href="../../synchronization/futures/future.html#future_wait"><code class="computeroutput">future::wait()</code></a>. That would block the helper fiber
until the <code class="computeroutput"><span class="identifier">future</span><span class="special">&lt;&gt;</span></code>
became ready, at which point we could <code class="computeroutput"><span class="identifier">push</span><span class="special">()</span></code> it to be retrieved by <code class="computeroutput"><span class="identifier">wait_first_outcome</span><span class="special">()</span></code>.
</p>
<p>
That would work &#8212; but there's a simpler tactic that avoids creating an extra
fiber. We can wrap the task function in a <a class="link" href="../../synchronization/futures/packaged_task.html#class_packaged_task"> <code class="computeroutput">packaged_task&lt;&gt;</code></a>.
fiber. We can wrap the task function in a <a class="link" href="../../synchronization/futures/packaged_task.html#class_packaged_task"><code class="computeroutput">packaged_task&lt;&gt;</code></a>.
While one naturally thinks of passing a <code class="computeroutput"><span class="identifier">packaged_task</span><span class="special">&lt;&gt;</span></code> to a new fiber &#8212; that is, in fact,
what <code class="computeroutput"><span class="identifier">async</span><span class="special">()</span></code>
does &#8212; in this case, we're already running in the helper fiber at the producer

View File

@@ -97,16 +97,16 @@
<p>
Instead of retrieving only the first <code class="computeroutput"><span class="identifier">future</span><span class="special">&lt;&gt;</span></code> from the channel, we must now loop
over <code class="computeroutput"><span class="identifier">future</span><span class="special">&lt;&gt;</span></code>
items. Of course we must limit that iteration! If we launch only <code class="computeroutput"><span class="identifier">count</span></code> producer fibers, the <code class="computeroutput"><span class="special">(</span><span class="identifier">count</span><span class="special">+</span><span class="number">1</span><span class="special">)</span></code>
<sup>st</sup>
<a class="link" href="../../synchronization/channels.html#unbounded_channel_pop"> <code class="computeroutput">unbounded_channel::pop()</code></a> call would block forever.
items. Of course we must limit that iteration! If we launch only <code class="computeroutput"><span class="identifier">count</span></code> producer fibers, the <code class="computeroutput"><span class="special">(</span><span class="identifier">count</span><span class="special">+</span><span class="number">1</span><span class="special">)</span></code><sup>st</sup>
<a class="link" href="../../synchronization/channels.html#unbounded_channel_pop"><code class="computeroutput">unbounded_channel::pop()</code></a> call
would block forever.
</p>
<p>
Given a ready <code class="computeroutput"><span class="identifier">future</span><span class="special">&lt;&gt;</span></code>,
we can distinguish failure by calling <a class="link" href="../../synchronization/futures/future.html#future_get_exception_ptr"> <code class="computeroutput">future::get_exception_ptr()</code></a>.
we can distinguish failure by calling <a class="link" href="../../synchronization/futures/future.html#future_get_exception_ptr"><code class="computeroutput">future::get_exception_ptr()</code></a>.
If the <code class="computeroutput"><span class="identifier">future</span><span class="special">&lt;&gt;</span></code>
in fact contains a result rather than an exception, <code class="computeroutput"><span class="identifier">get_exception_ptr</span><span class="special">()</span></code> returns <code class="computeroutput"><span class="keyword">nullptr</span></code>.
In that case, we can confidently call <a class="link" href="../../synchronization/futures/future.html#future_get"> <code class="computeroutput">future::get()</code></a> to return
In that case, we can confidently call <a class="link" href="../../synchronization/futures/future.html#future_get"><code class="computeroutput">future::get()</code></a> to return
that result to our caller.
</p>
<p>

View File

@@ -35,8 +35,8 @@
<p>
One tactic would be to adapt our <a class="link" href="when_any__simple_completion.html#wait_done"><code class="computeroutput"><span class="identifier">Done</span></code></a> class to store the first
of the return values, rather than a simple <code class="computeroutput"><span class="keyword">bool</span></code>.
However, we choose instead to use a <a class="link" href="../../synchronization/channels.html#class_unbounded_channel"> <code class="computeroutput">unbounded_channel&lt;&gt;</code></a>.
We'll only need to enqueue the first value, so we'll <a class="link" href="../../synchronization/channels.html#unbounded_channel_close"> <code class="computeroutput">unbounded_channel::close()</code></a> it
However, we choose instead to use a <a class="link" href="../../synchronization/channels.html#class_unbounded_channel"><code class="computeroutput">unbounded_channel&lt;&gt;</code></a>.
We'll only need to enqueue the first value, so we'll <a class="link" href="../../synchronization/channels.html#unbounded_channel_close"><code class="computeroutput">unbounded_channel::close()</code></a> it
once we've retrieved that value. Subsequent <code class="computeroutput"><span class="identifier">push</span><span class="special">()</span></code> calls will return <code class="computeroutput"><span class="identifier">closed</span></code>.
</p>
<p>

View File

@@ -35,7 +35,7 @@
<p>
<a name="wait_done"></a>For this we introduce a <code class="computeroutput"><span class="identifier">Done</span></code>
class to wrap a <code class="computeroutput"><span class="keyword">bool</span></code> variable
with a <a class="link" href="../../synchronization/conditions.html#class_condition_variable"> <code class="computeroutput">condition_variable</code></a> and a <a class="link" href="../../synchronization/mutex_types.html#class_mutex"> <code class="computeroutput">mutex</code></a>:
with a <a class="link" href="../../synchronization/conditions.html#class_condition_variable"><code class="computeroutput">condition_variable</code></a> and a <a class="link" href="../../synchronization/mutex_types.html#class_mutex"><code class="computeroutput">mutex</code></a>:
</p>
<p>
</p>

View File

@@ -18,6 +18,13 @@ fiber/synchronization/futures/packaged_task.html
fiber/fls.html
fiber/migration.html
fiber/callbacks.html
fiber/callbacks/overview.html
fiber/callbacks/return_errorcode.html
fiber/callbacks/success_or_exception.html
fiber/callbacks/return_errorcode_or_data.html
fiber/callbacks/data_or_exception.html
fiber/callbacks/success_error_virtual_methods.html
fiber/callbacks/then_there_s____boost_asio__.html
fiber/nonblocking.html
fiber/when_any.html
fiber/when_any/when_any.html
@@ -34,6 +41,10 @@ fiber/when_any/when_all_functionality/when_all_until_first_exception.html
fiber/when_any/when_all_functionality/wait_all__collecting_all_exceptions.html
fiber/when_any/when_all_functionality/when_all__heterogeneous_types.html
fiber/integration.html
fiber/integration/overview.html
fiber/integration/event_driven_program.html
fiber/integration/embedded_main_loop.html
fiber/integration/deeper_dive_into___boost_asio__.html
fiber/performance.html
fiber/custom.html
fiber/rationale.html

View File

@@ -66,6 +66,19 @@
between threads</a></span></dt>
<dt><span class="section"><a href="fiber/callbacks.html">Integrating Fibers
with Asynchronous Callbacks</a></span></dt>
<dd><dl>
<dt><span class="section"><a href="fiber/callbacks/overview.html">Overview</a></span></dt>
<dt><span class="section"><a href="fiber/callbacks/return_errorcode.html">Return Errorcode</a></span></dt>
<dt><span class="section"><a href="fiber/callbacks/success_or_exception.html">Success or Exception</a></span></dt>
<dt><span class="section"><a href="fiber/callbacks/return_errorcode_or_data.html">Return Errorcode
or Data</a></span></dt>
<dt><span class="section"><a href="fiber/callbacks/data_or_exception.html">Data
or Exception</a></span></dt>
<dt><span class="section"><a href="fiber/callbacks/success_error_virtual_methods.html">Success/Error
Virtual Methods</a></span></dt>
<dt><span class="section"><a href="fiber/callbacks/then_there_s____boost_asio__.html">Then
There&#8217;s <a href="http://www.boost.org/doc/libs/release/libs/asio/index.html" target="_top">Boost.Asio</a></a></span></dt>
</dl></dd>
<dt><span class="section"><a href="fiber/nonblocking.html">Integrating
Fibers with Nonblocking I/O</a></span></dt>
<dt><span class="section"><a href="fiber/when_any.html">when_any / when_all
@@ -102,6 +115,15 @@
</dl></dd>
<dt><span class="section"><a href="fiber/integration.html">Sharing a
Thread with Another Main Loop</a></span></dt>
<dd><dl>
<dt><span class="section"><a href="fiber/integration/overview.html">Overview</a></span></dt>
<dt><span class="section"><a href="fiber/integration/event_driven_program.html">Event-Driven
Program</a></span></dt>
<dt><span class="section"><a href="fiber/integration/embedded_main_loop.html">Embedded
Main Loop</a></span></dt>
<dt><span class="section"><a href="fiber/integration/deeper_dive_into___boost_asio__.html">Deeper
Dive into <a href="http://www.boost.org/doc/libs/release/libs/asio/index.html" target="_top">Boost.Asio</a></a></span></dt>
</dl></dd>
<dt><span class="section"><a href="fiber/performance.html">Performance</a></span></dt>
<dt><span class="section"><a href="fiber/custom.html">Customization</a></span></dt>
<dt><span class="section"><a href="fiber/rationale.html">Rationale</a></span></dt>
@@ -111,7 +133,7 @@
</div>
</div>
<table xmlns:rev="http://www.cs.rpi.edu/~gregod/boost/tools/doc/revision" width="100%"><tr>
<td align="left"><p><small>Last revised: March 28, 2016 at 18:28:49 GMT</small></p></td>
<td align="left"><p><small>Last revised: May 01, 2016 at 07:21:27 GMT</small></p></td>
<td align="right"><div class="copyright-footer"></div></td>
</tr></table>
<hr>

View File

@@ -25,31 +25,31 @@ __boost_fiber__ because certain asynchronous I/O sequences are logically
sequential, and for those you want to write and maintain code that looks and
acts sequential.
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
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.
You must ensure that the application's main loop ['itself] doesn't monopolize
You must ensure that the application[s] main loop ['itself] doesn[t] monopolize
the processor: that the fibers it launches will get the CPU cycles they need.
The solution is the same as for any fiber that might claim the CPU for an
extended time: introduce calls to [ns_function_link this_fiber..yield]. The
most straightforward approach is to call `yield()` on every iteration of your
existing main loop. In effect, this unifies the application's main loop with
__boost_fiber__'s internal main loop. `yield()` allows the fiber manager to
existing main loop. In effect, this unifies the application[s] main loop with
__boost_fiber__[s] internal main loop. `yield()` 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 `yield()` and resumes the
application's main loop.
application[s] main loop. When these fibers have had a turn, control passes to
the thread[s] main fiber, which returns from `yield()` and resumes the
application[s] main loop.
[endsect]
[#embedded_main_loop]
[section Embedded Main Loop]
More challenging is when the application's main loop is embedded in some other
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 `run()` function from which
control does not return until application shutdown.

View File

@@ -77,11 +77,10 @@ See also [link migration Migrating fibers between threads].
[heading support for Boost.Asio]
Support for __boost_asio__'s __async_result__ is not part of the official API.
However, to integrate with a `boost::asio::io_service`, see [link integration
Sharing a Thread with Another Main Loop]. To interface smoothly with an
arbitrary Asio async I/O operation, see [link callbacks_asio Then There's
__boost_asio__].
Support for __boost_asio__[s] __async_result__ is not part of the official API.
However, to integrate with a __io_service__, see [link integration Sharing a
Thread with Another Main Loop]. To interface smoothly with an arbitrary Asio
async I/O operation, see [link callbacks_asio Then There[s] __boost_asio__].
[heading tested compilers]

View File

@@ -302,7 +302,7 @@ Certain topics in C++ can arouse strong passions, and exceptions are no
exception. We cannot resist mentioning [mdash] for purely informational
purposes [mdash] that when you need only the ['first] result from some number
of concurrently-running fibers, it would be possible to pass a
[`shared_ptr<[template_link promise]>] to the participating fibers, then cause
[^shared_ptr<[template_link promise]>] to the participating fibers, then cause
the initiating fiber to call [member_link future..get] on its [template_link
future]. The first fiber to call [member_link promise..set_value] on that
shared `promise` will succeed; subsequent `set_value()` calls on the same