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:
@@ -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
|
||||
|
||||
@@ -33,69 +33,75 @@
|
||||
[def __not_a_fiber__ ['not-a-fiber]]
|
||||
[def __rendezvous__ ['rendezvous]]
|
||||
|
||||
[template mdash[] '''—''']
|
||||
[template "[text] '''“'''[text]'''”''']
|
||||
[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[]'''—''']
|
||||
[template ,[]'''’''']
|
||||
[template "[text]'''“'''[text]'''”''']
|
||||
[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]]
|
||||
|
||||
3411
doc/fibers.xml
3411
doc/fibers.xml
File diff suppressed because it is too large
Load Diff
@@ -7,7 +7,7 @@
|
||||
<link rel="home" href="../index.html" title="Chapter 1. Fiber">
|
||||
<link rel="up" href="../index.html" title="Chapter 1. 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">&</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"><</span> <span class="keyword">void</span><span class="special">(</span> <span class="identifier">errorcode</span><span class="special">)</span> <span class="special">></span> <span class="keyword">const</span><span class="special">&</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"><</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">&)</span> <span class="special">></span> <span class="keyword">const</span><span class="special">&);</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<></code></a> and <a class="link" href="synchronization/futures/future.html#class_future"> <code class="computeroutput">future<></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<></code></a> and
|
||||
<a class="link" href="synchronization/futures/future.html#class_future"> <code class="computeroutput">future<></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">&</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">&</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"><</span> <span class="identifier">AsyncAPI</span><span class="special">::</span><span class="identifier">errorcode</span> <span class="special">></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"><</span> <span class="identifier">AsyncAPI</span><span class="special">::</span><span class="identifier">errorcode</span> <span class="special">></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">[&</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"><></span></code>
|
||||
of correct type.
|
||||
</li>
|
||||
<li class="listitem">
|
||||
Obtain its <code class="computeroutput"><span class="identifier">future</span><span class="special"><></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">&</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">&</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"><></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"><</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">></span> <span class="identifier">read_ec</span><span class="special">(</span> <span class="identifier">AsyncAPI</span> <span class="special">&</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"><</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">></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"><</span> <span class="identifier">result_pair</span> <span class="special">></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"><</span> <span class="identifier">result_pair</span> <span class="special">></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">([&</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">&</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"><></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">&</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"><</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">string</span> <span class="special">></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"><</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">string</span> <span class="special">></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">([&</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">&</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"><</span> <span class="identifier">Response</span> <span class="special">></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">&</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">&</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"><</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">string</span> <span class="special">></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"><</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">string</span> <span class="special">></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"><></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">&</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"><</span> <span class="identifier">PromiseResponse</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"><</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">string</span> <span class="special">></span> <span class="identifier">future</span><span class="special">(</span> <span class="identifier">promisep</span><span class="special">-></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"><</span> <span class="special">...,</span> <span class="keyword">class</span> <span class="identifier">CompletionToken</span> <span class="special">></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">&&</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"><</span><span class="identifier">CompletionToken</span><span class="special">,</span> <span class="special">...>::</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"><</span><span class="keyword">decltype</span><span class="special">(</span><span class="identifier">handler</span><span class="special">)></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"><></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">&</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">&</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>
|
||||
— <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"><></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<void>. 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"><</span> <span class="keyword">typename</span> <span class="identifier">ReturnType</span> <span class="special">></span>
|
||||
<span class="keyword">struct</span> <span class="identifier">handler_type</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_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">></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"><</span> <span class="keyword">void</span> <span class="special">></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"><</span><span class="identifier">T</span><span class="special">></span></code>
|
||||
implementation and a <code class="computeroutput"><span class="identifier">yield_handler</span><span class="special"><</span><span class="keyword">void</span><span class="special">></span></code>
|
||||
specialization. Let's start with the <code class="computeroutput"><span class="special"><</span><span class="keyword">void</span><span class="special">></span></code> specialization:
|
||||
</p>
|
||||
<p>
|
||||
</p>
|
||||
<pre class="programlisting"><span class="comment">// yield_handler<void> is like yield_handler<T> without value_. In fact it's</span>
|
||||
<span class="comment">// just like yield_handler_base.</span>
|
||||
<span class="keyword">template</span><span class="special"><></span>
|
||||
<span class="keyword">class</span> <span class="identifier">yield_handler</span><span class="special"><</span> <span class="keyword">void</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="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">&</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"><></span></code> traits specialization, instantiates
|
||||
a <code class="computeroutput"><span class="identifier">yield_handler</span><span class="special"><</span><span class="keyword">void</span><span class="special">></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<T> (capturing</span>
|
||||
<span class="comment">// a value to return from asio async function) and yield_handler<void> (no</span>
|
||||
<span class="comment">// such value). See yield_handler<T> and its <void> specialization below. Both</span>
|
||||
<span class="comment">// yield_handler<T> and yield_handler<void> 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<yield_handler<>> 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">&</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">&</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">-></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">-></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">-></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">&&</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">()-></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">()-></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
|
||||
— 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 — 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"><</span><span class="keyword">void</span><span class="special">></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"><>::</span><span class="identifier">type</span></code>:
|
||||
in this case, <code class="computeroutput"><span class="identifier">async_result</span><span class="special"><</span><span class="identifier">yield_handler</span><span class="special"><</span><span class="keyword">void</span><span class="special">>></span></code>.
|
||||
It passes the <code class="computeroutput"><span class="identifier">yield_handler</span><span class="special"><</span><span class="keyword">void</span><span class="special">></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<void></span>
|
||||
<span class="comment">// specialization is just like async_result_base.</span>
|
||||
<span class="keyword">template</span><span class="special"><></span>
|
||||
<span class="keyword">class</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"><</span> <span class="keyword">void</span> <span class="special">></span> <span class="special">></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"><</span> <span class="keyword">void</span> <span class="special">></span> <span class="special">&</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<yield_handler<T>> and</span>
|
||||
<span class="comment">// async_result<yield_handler<void>></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">&</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<>.</span>
|
||||
<span class="identifier">h</span><span class="special">.</span><span class="identifier">ycomp_</span> <span class="special">=</span> <span class="special">&</span> <span class="keyword">this</span><span class="special">-></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">&</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<>, async_result<> 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"><</span><span class="keyword">void</span><span class="special">></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"><</span><span class="identifier">yield_handler</span><span class="special"><</span><span class="keyword">void</span><span class="special">>>::</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"><</span><span class="identifier">yield_handler</span><span class="special"><</span><span class="keyword">void</span><span class="special">>>::</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"><</span> <span class="identifier">mutex_t</span> <span class="special">></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<spinlock>) 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">()-></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"><</span><span class="keyword">void</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">&)</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"><</span><span class="keyword">void</span><span class="special">></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">&)</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">&)</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 — 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>
|
||||
— 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">“<span class="quote">hop</span>”</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 — 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 — 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 — 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 — <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"><</span><span class="keyword">void</span><span class="special">>::</span><span class="keyword">operator</span><span class="special">()()</span></code> invokes the machinery above with a <span class="quote">“<span class="quote">success</span>”</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"><>::</span><span class="identifier">type</span></code>
|
||||
specifies <code class="computeroutput"><span class="identifier">yield_handler</span><span class="special"><</span><span class="identifier">T</span><span class="special">></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"><</span><span class="identifier">T</span><span class="special">></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<completion token type, signature>::type to decide</span>
|
||||
<span class="comment">// what to instantiate as the actual handler. Below, we specialize</span>
|
||||
<span class="comment">// handler_type< yield_t, ... > to indicate yield_handler<>. 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<> as the actual handler class.</span>
|
||||
<span class="keyword">template</span><span class="special"><</span> <span class="keyword">typename</span> <span class="identifier">T</span> <span class="special">></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">&</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">&</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<T>::operator()()"</span><span class="special">);</span>
|
||||
<span class="comment">// move the value to async_result<> 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"><</span><span class="identifier">yield_handler</span><span class="special"><</span><span class="identifier">T</span><span class="special">>></span></code>:
|
||||
</p>
|
||||
<p>
|
||||
</p>
|
||||
<pre class="programlisting"><span class="comment">// asio constructs an async_result<> instance from the yield_handler specified</span>
|
||||
<span class="comment">// by handler_type<>::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"><</span> <span class="keyword">typename</span> <span class="identifier">T</span> <span class="special">></span>
|
||||
<span class="keyword">class</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"><</span> <span class="identifier">T</span> <span class="special">></span> <span class="special">></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"><</span> <span class="identifier">T</span> <span class="special">></span> <span class="special">&</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<>: 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">&</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"><></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"><</span><span class="identifier">T</span><span class="special">>::</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"><</span><span class="identifier">yield_handler</span><span class="special"><</span><span class="identifier">T</span><span class="special">>></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"><</span><span class="identifier">T</span><span class="special">>::</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"><</span><span class="identifier">yield_handler</span><span class="special"><</span><span class="identifier">T</span><span class="special">>>::</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"><</span><span class="identifier">yield_handler</span><span class="special"><</span><span class="identifier">T</span><span class="special">>>::</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"><</span><span class="identifier">T</span><span class="special">>::</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">“<span class="quote">success</span>”</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’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>
|
||||
|
||||
78
doc/html/fiber/callbacks/data_or_exception.html
Normal file
78
doc/html/fiber/callbacks/data_or_exception.html
Normal 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 1. 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’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">&</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"><</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">string</span> <span class="special">></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"><</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">string</span> <span class="special">></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">([&</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">&</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 © 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>
|
||||
106
doc/html/fiber/callbacks/overview.html
Normal file
106
doc/html/fiber/callbacks/overview.html
Normal 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 1. 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">&</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"><</span> <span class="keyword">void</span><span class="special">(</span> <span class="identifier">errorcode</span><span class="special">)</span> <span class="special">></span> <span class="keyword">const</span><span class="special">&</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"><</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">&)</span> <span class="special">></span> <span class="keyword">const</span><span class="special">&);</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<></code></a> and <a class="link" href="../synchronization/futures/future.html#class_future"><code class="computeroutput">future<></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 © 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>
|
||||
103
doc/html/fiber/callbacks/return_errorcode.html
Normal file
103
doc/html/fiber/callbacks/return_errorcode.html
Normal 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 1. 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<></code></a> and
|
||||
<a class="link" href="../synchronization/futures/future.html#class_future"><code class="computeroutput">future<></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">&</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">&</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"><</span> <span class="identifier">AsyncAPI</span><span class="special">::</span><span class="identifier">errorcode</span> <span class="special">></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"><</span> <span class="identifier">AsyncAPI</span><span class="special">::</span><span class="identifier">errorcode</span> <span class="special">></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">[&</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"><></span></code> of correct type.
|
||||
</li>
|
||||
<li class="listitem">
|
||||
Obtain its <code class="computeroutput"><span class="identifier">future</span><span class="special"><></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>
|
||||
</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 © 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>
|
||||
75
doc/html/fiber/callbacks/return_errorcode_or_data.html
Normal file
75
doc/html/fiber/callbacks/return_errorcode_or_data.html
Normal 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 1. 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’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"><></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"><</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">></span> <span class="identifier">read_ec</span><span class="special">(</span> <span class="identifier">AsyncAPI</span> <span class="special">&</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"><</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">></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"><</span> <span class="identifier">result_pair</span> <span class="special">></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"><</span> <span class="identifier">result_pair</span> <span class="special">></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">([&</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">&</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"><></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 © 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>
|
||||
131
doc/html/fiber/callbacks/success_error_virtual_methods.html
Normal file
131
doc/html/fiber/callbacks/success_error_virtual_methods.html
Normal 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 1. 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’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"><</span> <span class="identifier">Response</span> <span class="special">></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">&</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">&</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"><</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">string</span> <span class="special">></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"><</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">string</span> <span class="special">></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"><></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">&</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"><</span> <span class="identifier">PromiseResponse</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"><</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">string</span> <span class="special">></span> <span class="identifier">future</span><span class="special">(</span> <span class="identifier">promisep</span><span class="special">-></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 © 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>
|
||||
63
doc/html/fiber/callbacks/success_or_exception.html
Normal file
63
doc/html/fiber/callbacks/success_or_exception.html
Normal 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 1. 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">&</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">&</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 © 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>
|
||||
606
doc/html/fiber/callbacks/then_there_s____boost_asio__.html
Normal file
606
doc/html/fiber/callbacks/then_there_s____boost_asio__.html
Normal file
@@ -0,0 +1,606 @@
|
||||
<html>
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=US-ASCII">
|
||||
<title>Then There’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 1. 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’s Boost.Asio">Then
|
||||
There’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"><</span> <span class="special">...,</span> <span class="keyword">class</span> <span class="identifier">CompletionToken</span> <span class="special">></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">&&</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"><</span><span class="identifier">CompletionToken</span><span class="special">,</span> <span class="special">...>::</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"><</span><span class="keyword">decltype</span><span class="special">(</span><span class="identifier">handler</span><span class="special">)></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’s <code class="computeroutput"><span class="identifier">handler_type</span><span class="special"><></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">&</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">&</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"><></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<void>. 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"><</span> <span class="keyword">typename</span> <span class="identifier">ReturnType</span> <span class="special">></span>
|
||||
<span class="keyword">struct</span> <span class="identifier">handler_type</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_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">></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"><</span> <span class="keyword">void</span> <span class="special">></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’s a generic <code class="computeroutput"><span class="identifier">yield_handler</span><span class="special"><</span><span class="identifier">T</span><span class="special">></span></code>
|
||||
implementation and a <code class="computeroutput"><span class="identifier">yield_handler</span><span class="special"><</span><span class="keyword">void</span><span class="special">></span></code>
|
||||
specialization. Let’s start with the <code class="computeroutput"><span class="special"><</span><span class="keyword">void</span><span class="special">></span></code> specialization:
|
||||
</p>
|
||||
<p>
|
||||
</p>
|
||||
<pre class="programlisting"><span class="comment">// yield_handler<void> is like yield_handler<T> without value_. In fact it's</span>
|
||||
<span class="comment">// just like yield_handler_base.</span>
|
||||
<span class="keyword">template</span><span class="special"><></span>
|
||||
<span class="keyword">class</span> <span class="identifier">yield_handler</span><span class="special"><</span> <span class="keyword">void</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="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">&</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"><></span></code> traits specialization, instantiates
|
||||
a <code class="computeroutput"><span class="identifier">yield_handler</span><span class="special"><</span><span class="keyword">void</span><span class="special">></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<T> (capturing</span>
|
||||
<span class="comment">// a value to return from asio async function) and yield_handler<void> (no</span>
|
||||
<span class="comment">// such value). See yield_handler<T> and its <void> specialization below. Both</span>
|
||||
<span class="comment">// yield_handler<T> and yield_handler<void> 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<yield_handler<>> 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">&</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">&</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">-></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">-></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">()-></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
|
||||
— 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 — 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"><</span><span class="keyword">void</span><span class="special">></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"><>::</span><span class="identifier">type</span></code>:
|
||||
in this case, <code class="computeroutput"><span class="identifier">async_result</span><span class="special"><</span><span class="identifier">yield_handler</span><span class="special"><</span><span class="keyword">void</span><span class="special">>></span></code>.
|
||||
It passes the <code class="computeroutput"><span class="identifier">yield_handler</span><span class="special"><</span><span class="keyword">void</span><span class="special">></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<void></span>
|
||||
<span class="comment">// specialization is just like async_result_base.</span>
|
||||
<span class="keyword">template</span><span class="special"><></span>
|
||||
<span class="keyword">class</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"><</span> <span class="keyword">void</span> <span class="special">></span> <span class="special">></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"><</span> <span class="keyword">void</span> <span class="special">></span> <span class="special">&</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<yield_handler<T>> and</span>
|
||||
<span class="comment">// async_result<yield_handler<void>></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">&</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<>.</span>
|
||||
<span class="identifier">h</span><span class="special">.</span><span class="identifier">ycomp_</span> <span class="special">=</span> <span class="special">&</span> <span class="keyword">this</span><span class="special">-></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">&</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<>, async_result<> 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 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>’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"><</span><span class="keyword">void</span><span class="special">></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"><</span><span class="identifier">yield_handler</span><span class="special"><</span><span class="keyword">void</span><span class="special">>>::</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"><</span><span class="identifier">yield_handler</span><span class="special"><</span><span class="keyword">void</span><span class="special">>>::</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"><</span> <span class="identifier">mutex_t</span> <span class="special">></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<spinlock>) 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">()-></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"><</span><span class="keyword">void</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">&)</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"><</span><span class="keyword">void</span><span class="special">></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">&)</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">&)</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 — 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>
|
||||
— 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>
|
||||
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’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 — 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 — <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"><</span><span class="keyword">void</span><span class="special">>::</span><span class="keyword">operator</span><span class="special">()()</span></code>
|
||||
invokes the machinery above with a <span class="quote">“<span class="quote">success</span>”</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"><>::</span><span class="identifier">type</span></code>
|
||||
specifies <code class="computeroutput"><span class="identifier">yield_handler</span><span class="special"><</span><span class="identifier">T</span><span class="special">></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"><</span><span class="identifier">T</span><span class="special">></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<completion token type, signature>::type to decide</span>
|
||||
<span class="comment">// what to instantiate as the actual handler. Below, we specialize</span>
|
||||
<span class="comment">// handler_type< yield_t, ... > to indicate yield_handler<>. 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<> as the actual handler class.</span>
|
||||
<span class="keyword">template</span><span class="special"><</span> <span class="keyword">typename</span> <span class="identifier">T</span> <span class="special">></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">&</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">&</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<T>::operator()()"</span><span class="special">);</span>
|
||||
<span class="comment">// move the value to async_result<> 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"><</span><span class="identifier">yield_handler</span><span class="special"><</span><span class="identifier">T</span><span class="special">>></span></code>:
|
||||
</p>
|
||||
<p>
|
||||
</p>
|
||||
<pre class="programlisting"><span class="comment">// asio constructs an async_result<> instance from the yield_handler specified</span>
|
||||
<span class="comment">// by handler_type<>::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"><</span> <span class="keyword">typename</span> <span class="identifier">T</span> <span class="special">></span>
|
||||
<span class="keyword">class</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"><</span> <span class="identifier">T</span> <span class="special">></span> <span class="special">></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"><</span> <span class="identifier">T</span> <span class="special">></span> <span class="special">&</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<>: 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">&</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"><></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"><</span><span class="identifier">T</span><span class="special">>::</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"><</span><span class="identifier">yield_handler</span><span class="special"><</span><span class="identifier">T</span><span class="special">>></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"><</span><span class="identifier">T</span><span class="special">>::</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"><</span><span class="identifier">yield_handler</span><span class="special"><</span><span class="identifier">T</span><span class="special">>>::</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"><</span><span class="identifier">yield_handler</span><span class="special"><</span><span class="identifier">T</span><span class="special">>>::</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"><</span><span class="identifier">T</span><span class="special">>::</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">“<span class="quote">success</span>”</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 © 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>
|
||||
@@ -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<></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<></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"><>()</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"><>()</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"><>()</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
|
||||
|
||||
@@ -66,12 +66,6 @@
|
||||
<span class="keyword">template</span><span class="special"><</span> <span class="keyword">typename</span> <span class="identifier">PROPS</span> <span class="special">></span>
|
||||
<span class="identifier">PROPS</span> <span class="special">&</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<></code></a> or
|
||||
<a class="link" href="synchronization/futures/packaged_task.html#class_packaged_task"> <code class="computeroutput">packaged_task<></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<></code></a> or
|
||||
<a class="link" href="synchronization/futures/packaged_task.html#class_packaged_task"><code class="computeroutput">packaged_task<></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<></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<></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>
|
||||
— 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>
|
||||
|
||||
@@ -38,9 +38,15 @@
|
||||
<span class="keyword">template</span><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">></span>
|
||||
<span class="identifier">fiber</span><span class="special">(</span> <span class="identifier">Fn</span> <span class="special">&&,</span> <span class="identifier">Args</span> <span class="special">&&</span> <span class="special">...);</span>
|
||||
|
||||
<span class="keyword">template</span><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">></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">&&,</span> <span class="identifier">Args</span> <span class="special">&&</span> <span class="special">...);</span>
|
||||
|
||||
<span class="keyword">template</span><span class="special"><</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">></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">&&,</span> <span class="identifier">Args</span> <span class="special">&&</span> <span class="special">...);</span>
|
||||
|
||||
<span class="keyword">template</span><span class="special"><</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">></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">&&,</span> <span class="identifier">Args</span> <span class="special">&&</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">&)</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"><</span> <span class="keyword">typename</span> <span class="identifier">PROPS</span> <span class="special">></span>
|
||||
<span class="identifier">PROPS</span> <span class="special">&</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"><</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">></span>
|
||||
<span class="identifier">fiber</span><span class="special">(</span> <span class="identifier">Fn</span> <span class="special">&&</span> <span class="identifier">fn</span><span class="special">,</span> <span class="identifier">Args</span> <span class="special">&&</span> <span class="special">...</span> <span class="identifier">args</span><span class="special">);</span>
|
||||
|
||||
<span class="keyword">template</span><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">></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">&&</span> <span class="identifier">fn</span><span class="special">,</span> <span class="identifier">Args</span> <span class="special">&&</span> <span class="special">...</span> <span class="identifier">args</span><span class="special">);</span>
|
||||
|
||||
<span class="keyword">template</span><span class="special"><</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">></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">&&</span> <span class="identifier">fn</span><span class="special">,</span> <span class="identifier">Args</span> <span class="special">&&</span> <span class="special">...</span> <span class="identifier">args</span><span class="special">);</span>
|
||||
|
||||
<span class="keyword">template</span><span class="special"><</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">></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">&&</span> <span class="identifier">fn</span><span class="special">,</span> <span class="identifier">Args</span> <span class="special">&&</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">“<span class="quote">ready</span>”</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">-></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<></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<></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<></code></a> provides
|
||||
<a class="link" href="../scheduling.html#class_sched_algorithm_with_properties"><code class="computeroutput">sched_algorithm_with_properties<></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>
|
||||
|
||||
@@ -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"><</span> <span class="keyword">typename</span> <span class="identifier">PROPS</span> <span class="special">></span>
|
||||
<span class="identifier">PROPS</span> <span class="special">&</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<></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<></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<></code></a> provides
|
||||
<a class="link" href="../scheduling.html#class_sched_algorithm_with_properties"><code class="computeroutput">sched_algorithm_with_properties<></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"><</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">></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"><</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">></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"><</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">></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"><</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">></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">&)</span> <span class="special">=</span> <span class="keyword">delete</span><span class="special">;</span>
|
||||
<span class="identifier">disable_interruption</span><span class="special">&</span> <span class="keyword">operator</span><span class="special">=(</span><span class="keyword">const</span> <span class="identifier">disable_interruption</span><span class="special">&)</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"><</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">></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">&)</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">&)</span> <span class="special">=</span> <span class="keyword">delete</span><span class="special">;</span>
|
||||
<span class="identifier">restore_interruption</span><span class="special">&</span> <span class="keyword">operator</span><span class="special">=(</span><span class="keyword">const</span> <span class="identifier">restore_interruption</span><span class="special">&)</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">&</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>
|
||||
|
||||
@@ -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">-></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>
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
<link rel="home" href="../index.html" title="Chapter 1. Fiber">
|
||||
<link rel="up" href="../index.html" title="Chapter 1. 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">“<span class="quote">starve</span>”</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">&)</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>
|
||||
|
||||
445
doc/html/fiber/integration/deeper_dive_into___boost_asio__.html
Normal file
445
doc/html/fiber/integration/deeper_dive_into___boost_asio__.html
Normal 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 1. 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’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
|
||||
— but that timer’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’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’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’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"><</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">>(</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">&</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">&</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"><</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">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">&</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">([&</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">&)</span> <span class="special">=</span> <span class="keyword">delete</span><span class="special">;</span>
|
||||
<span class="identifier">service</span> <span class="special">&</span> <span class="keyword">operator</span><span class="special">=(</span> <span class="identifier">service</span> <span class="keyword">const</span><span class="special">&)</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<<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>></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’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>’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"><</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’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 — 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>’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 — once
|
||||
we reach a state in which no fiber is ready —
|
||||
that would cause the thread to
|
||||
spin.
|
||||
</p>
|
||||
<p>
|
||||
We could, of course, set an Asio timer — again as <a class="link" href="embedded_main_loop.html#embedded_main_loop">previously
|
||||
discussed</a>. But in this <span class="quote">“<span class="quote">deeper dive,</span>”</span> we’re trying to
|
||||
do a little better.
|
||||
</p>
|
||||
<p>
|
||||
The key to doing better is that since we’re in a fiber, we can run an actual
|
||||
loop — not just a chain of callbacks. We can wait for <span class="quote">“<span class="quote">something to happen</span>”</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>
|
||||
— 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’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
|
||||
— no matter which — <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’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’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’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">&</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">&){});</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’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’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’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 © 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>
|
||||
77
doc/html/fiber/integration/embedded_main_loop.html
Normal file
77
doc/html/fiber/integration/embedded_main_loop.html
Normal 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 1. 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’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 © 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>
|
||||
73
doc/html/fiber/integration/event_driven_program.html
Normal file
73
doc/html/fiber/integration/event_driven_program.html
Normal 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 1. 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’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>
|
||||
</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 © 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>
|
||||
48
doc/html/fiber/integration/overview.html
Normal file
48
doc/html/fiber/integration/overview.html
Normal 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 1. 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">“<span class="quote">starve</span>”</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 © 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>
|
||||
@@ -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">“<span class="quote">main</span>”</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 — 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>
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
<meta name="generator" content="DocBook XSL Stylesheets V1.75.2">
|
||||
<link rel="home" href="../index.html" title="Chapter 1. Fiber">
|
||||
<link rel="up" href="../index.html" title="Chapter 1. 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’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>
|
||||
|
||||
@@ -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<></code></a> instead.
|
||||
value. Use <a class="link" href="synchronization/futures/future.html#class_future"><code class="computeroutput">future<></code></a> instead.
|
||||
</p>
|
||||
<p>
|
||||
Similarly, a fiber that invokes a normal blocking I/O operation will block
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
<meta name="generator" content="DocBook XSL Stylesheets V1.75.2">
|
||||
<link rel="home" href="../index.html" title="Chapter 1. Fiber">
|
||||
<link rel="up" href="../index.html" title="Chapter 1. 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 1.7. 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>
|
||||
|
||||
@@ -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
|
||||
— 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>’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’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">“<span class="quote">Programming with POSIX Threads</span>”</span>
|
||||
</p></div>
|
||||
</div>
|
||||
|
||||
@@ -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"><</span> <span class="identifier">my_fiber_scheduler</span> <span class="special">>();</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>
|
||||
— or <a class="link" href="scheduling.html#sched_algorithm_notify"> <code class="computeroutput">sched_algorithm::notify()</code></a> is called — whichever
|
||||
— or <a class="link" href="scheduling.html#sched_algorithm_notify"><code class="computeroutput">sched_algorithm::notify()</code></a> is called — 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"><</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">></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<></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<></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"><</span><span class="identifier">PROPS</span><span class="special">></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"><</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">></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">“<span class="quote">main</span>”</span> or <span class="quote">“<span class="quote">dispatching</span>”</span> fiber — 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>
|
||||
— must never be passed to <a class="link" href="scheduling.html#context_migrate"> <code class="computeroutput">context::migrate()</code></a> for any other
|
||||
— 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>
|
||||
|
||||
@@ -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"><></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>
|
||||
|
||||
@@ -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">“<span class="quote">simultaneously,</span>”</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
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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"><</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">></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"><</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">></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>
|
||||
|
||||
@@ -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<></code></a> and
|
||||
<a class="link" href="futures/future.html#class_shared_future"> <code class="computeroutput">shared_future<></code></a> which are used to retrieve the asynchronous
|
||||
results, and <a class="link" href="futures/promise.html#class_promise"> <code class="computeroutput">promise<></code></a> and <a class="link" href="futures/packaged_task.html#class_packaged_task"> <code class="computeroutput">packaged_task<></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<></code></a> and
|
||||
<a class="link" href="futures/future.html#class_shared_future"><code class="computeroutput">shared_future<></code></a> which are used to retrieve the asynchronous
|
||||
results, and <a class="link" href="futures/promise.html#class_promise"><code class="computeroutput">promise<></code></a> and <a class="link" href="futures/packaged_task.html#class_packaged_task"><code class="computeroutput">packaged_task<></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<></code></a> holds the one and only reference
|
||||
An instance of <a class="link" href="futures/future.html#class_future"><code class="computeroutput">future<></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<></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<></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<></code></a> into an instance
|
||||
of <a class="link" href="futures/future.html#class_shared_future"> <code class="computeroutput">shared_future<></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<></code></a> into an instance
|
||||
of <a class="link" href="futures/future.html#class_shared_future"><code class="computeroutput">shared_future<></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<></code></a> that will deliver
|
||||
spawns a fiber and returns a <a class="link" href="futures/future.html#class_future"><code class="computeroutput">future<></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<></code></a> or
|
||||
a <a class="link" href="futures/packaged_task.html#class_packaged_task"> <code class="computeroutput">packaged_task<></code></a>. A <a class="link" href="futures/packaged_task.html#class_packaged_task"> <code class="computeroutput">packaged_task<></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<></code></a> or
|
||||
a <a class="link" href="futures/packaged_task.html#class_packaged_task"><code class="computeroutput">packaged_task<></code></a>. A <a class="link" href="futures/packaged_task.html#class_packaged_task"><code class="computeroutput">packaged_task<></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<></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<></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">“<span class="quote">How do
|
||||
I return a value from a fiber?</span>”</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<></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<></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<></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<></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.
|
||||
|
||||
@@ -35,21 +35,21 @@
|
||||
state</a>
|
||||
</h6>
|
||||
<p>
|
||||
Behind a <a class="link" href="promise.html#class_promise"> <code class="computeroutput">promise<></code></a> and its <a class="link" href="future.html#class_future"> <code class="computeroutput">future<></code></a> lies
|
||||
Behind a <a class="link" href="promise.html#class_promise"><code class="computeroutput">promise<></code></a> and its <a class="link" href="future.html#class_future"><code class="computeroutput">future<></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<></code></a>.
|
||||
The shared state is instantiated along with the <a class="link" href="promise.html#class_promise"><code class="computeroutput">promise<></code></a>.
|
||||
</p>
|
||||
<p>
|
||||
Aside from its originating <code class="computeroutput"><span class="identifier">promise</span><span class="special"><></span></code>, a <a class="link" href="future.html#class_future"> <code class="computeroutput">future<></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<></code></a> instances
|
||||
Aside from its originating <code class="computeroutput"><span class="identifier">promise</span><span class="special"><></span></code>, a <a class="link" href="future.html#class_future"><code class="computeroutput">future<></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<></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<></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<></code></a>, discussions of shared state
|
||||
As <a class="link" href="packaged_task.html#class_packaged_task"><code class="computeroutput">packaged_task<></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<></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<></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<></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"><</span> <span class="keyword">typename</span> <span class="identifier">R</span> <span class="special">></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<></code></a>
|
||||
instantiate <a class="link" href="promise.html#class_promise"><code class="computeroutput">promise<></code></a>
|
||||
</li>
|
||||
<li class="listitem">
|
||||
obtain its <code class="computeroutput"><span class="identifier">future</span><span class="special"><></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"><></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"><></span></code>
|
||||
</li>
|
||||
<li class="listitem">
|
||||
destroy <code class="computeroutput"><span class="identifier">future</span><span class="special"><></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<></code></a>.
|
||||
Move the state to a <a class="link" href="future.html#class_shared_future"><code class="computeroutput">shared_future<></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<></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<></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<></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<></code></a> instances.
|
||||
A <a class="link" href="future.html#class_shared_future"><code class="computeroutput">shared_future<></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<></code></a> instances.
|
||||
</p>
|
||||
<pre class="programlisting"><span class="keyword">template</span><span class="special"><</span> <span class="keyword">typename</span> <span class="identifier">R</span> <span class="special">></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">></span>
|
||||
<span class="identifier">async</span><span class="special">(</span> <span class="identifier">Function</span> <span class="special">&&</span> <span class="identifier">fn</span><span class="special">,</span> <span class="identifier">Args</span> <span class="special">&&</span> <span class="special">...</span> <span class="identifier">args</span><span class="special">);</span>
|
||||
|
||||
<span class="keyword">template</span><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">></span>
|
||||
<span class="identifier">future</span><span class="special"><</span>
|
||||
<span class="identifier">std</span><span class="special">::</span><span class="identifier">result_of_t</span><span class="special"><</span>
|
||||
<span class="identifier">std</span><span class="special">::</span><span class="identifier">decay_t</span><span class="special"><</span> <span class="identifier">Function</span> <span class="special">>(</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">decay_t</span><span class="special"><</span> <span class="identifier">Args</span> <span class="special">></span> <span class="special">...</span> <span class="special">)</span>
|
||||
<span class="special">></span>
|
||||
<span class="special">></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">&&</span> <span class="identifier">fn</span><span class="special">,</span> <span class="identifier">Args</span> <span class="special">&&</span> <span class="special">...</span> <span class="identifier">args</span><span class="special">);</span>
|
||||
|
||||
<span class="keyword">template</span><span class="special"><</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">></span>
|
||||
<span class="identifier">future</span><span class="special"><</span>
|
||||
<span class="identifier">std</span><span class="special">::</span><span class="identifier">result_of_t</span><span class="special"><</span>
|
||||
@@ -912,6 +910,15 @@
|
||||
<span class="special">></span>
|
||||
<span class="special">></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">&&</span> <span class="identifier">fn</span><span class="special">,</span> <span class="identifier">Args</span> <span class="special">&&</span> <span class="special">...</span> <span class="identifier">args</span><span class="special">);</span>
|
||||
|
||||
<span class="keyword">template</span><span class="special"><</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">></span>
|
||||
<span class="identifier">future</span><span class="special"><</span>
|
||||
<span class="identifier">std</span><span class="special">::</span><span class="identifier">result_of_t</span><span class="special"><</span>
|
||||
<span class="identifier">std</span><span class="special">::</span><span class="identifier">decay_t</span><span class="special"><</span> <span class="identifier">Function</span> <span class="special">>(</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">decay_t</span><span class="special"><</span> <span class="identifier">Args</span> <span class="special">></span> <span class="special">...</span> <span class="special">)</span>
|
||||
<span class="special">></span>
|
||||
<span class="special">></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">&&</span> <span class="identifier">fn</span><span class="special">,</span> <span class="identifier">Args</span> <span class="special">&&</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<></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<></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>
|
||||
|
||||
@@ -28,7 +28,7 @@
|
||||
<code class="computeroutput"><span class="identifier">packaged_task</span><span class="special"><></span></code></a>
|
||||
</h4></div></div></div>
|
||||
<p>
|
||||
A <a class="link" href="packaged_task.html#class_packaged_task"> <code class="computeroutput">packaged_task<></code></a> wraps a callable target that
|
||||
A <a class="link" href="packaged_task.html#class_packaged_task"><code class="computeroutput">packaged_task<></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<></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<></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"><></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"><></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"><></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"><</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">></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<></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<></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>
|
||||
|
||||
@@ -28,8 +28,8 @@
|
||||
<code class="computeroutput"><span class="identifier">promise</span><span class="special"><></span></code></a>
|
||||
</h4></div></div></div>
|
||||
<p>
|
||||
A <a class="link" href="promise.html#class_promise"> <code class="computeroutput">promise<></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<></code></a> object.
|
||||
A <a class="link" href="promise.html#class_promise"><code class="computeroutput">promise<></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<></code></a> object.
|
||||
<code class="computeroutput"><span class="identifier">promise</span><span class="special"><></span></code>
|
||||
and <code class="computeroutput"><span class="identifier">future</span><span class="special"><></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<></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<></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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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"><></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"><></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>
|
||||
|
||||
@@ -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"><</span><span class="identifier">unbounded_channel</span><span class="special"><</span><span class="identifier">T</span><span class="special">>></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"><</span><span class="identifier">unbounded_channel</span><span class="special"><</span><span class="identifier">T</span><span class="special">>></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<></code></a> or
|
||||
<a class="link" href="../../synchronization/channels.html#class_unbounded_channel"> <code class="computeroutput">unbounded_channel<></code></a>. We chose <code class="computeroutput"><span class="identifier">unbounded_channel</span><span class="special"><></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<></code></a> or
|
||||
<a class="link" href="../../synchronization/channels.html#class_unbounded_channel"><code class="computeroutput">unbounded_channel<></code></a>. We chose <code class="computeroutput"><span class="identifier">unbounded_channel</span><span class="special"><></span></code>
|
||||
on the assumption that its simpler semantics imply a cheaper implementation.
|
||||
</p></div>
|
||||
</div>
|
||||
|
||||
@@ -31,8 +31,8 @@
|
||||
For the case in which we must wait for <span class="emphasis"><em>all</em></span> task functions
|
||||
to complete — but we don't need results (or expect exceptions) from any of
|
||||
them — 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>
|
||||
|
||||
@@ -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"><</span> <span class="identifier">T</span> <span class="special">></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"><</span> <span class="identifier">T</span> <span class="special">></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>
|
||||
|
||||
@@ -31,13 +31,12 @@
|
||||
Certain topics in C++ can arouse strong passions, and exceptions are no
|
||||
exception. We cannot resist mentioning — for purely informational purposes
|
||||
— that when you need only the <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<
|
||||
<a class="link" href="../../synchronization/futures/promise.html#class_promise"> <code class="computeroutput">promise<></code></a>></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<></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<<a class="link" href="../../synchronization/futures/promise.html#class_promise"><code class="computeroutput">promise<></code></a>></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<></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>
|
||||
|
||||
@@ -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<></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<></code></a> to
|
||||
awaiting the first result. We can use <a class="link" href="../../synchronization/futures/future.html#class_future"><code class="computeroutput">future<></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<></code></a> to
|
||||
hold <code class="computeroutput"><span class="identifier">future</span><span class="special"><</span>
|
||||
<span class="identifier">T</span> <span class="special">></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"><></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 — but there's a timing issue. How should we obtain the <code class="computeroutput"><span class="identifier">future</span><span class="special"><></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"><></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"><></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"><></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"><></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 — 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<></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<></code></a>.
|
||||
While one naturally thinks of passing a <code class="computeroutput"><span class="identifier">packaged_task</span><span class="special"><></span></code> to a new fiber — that is, in fact,
|
||||
what <code class="computeroutput"><span class="identifier">async</span><span class="special">()</span></code>
|
||||
does — in this case, we're already running in the helper fiber at the producer
|
||||
|
||||
@@ -97,16 +97,16 @@
|
||||
<p>
|
||||
Instead of retrieving only the first <code class="computeroutput"><span class="identifier">future</span><span class="special"><></span></code> from the channel, we must now loop
|
||||
over <code class="computeroutput"><span class="identifier">future</span><span class="special"><></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"><></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"><></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>
|
||||
|
||||
@@ -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<></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<></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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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’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>
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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]
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user