mirror of
https://github.com/boostorg/fiber.git
synced 2026-02-15 00:52:34 +00:00
580 lines
57 KiB
HTML
580 lines
57 KiB
HTML
<html>
|
|
<head>
|
|
<meta http-equiv="Content-Type" content="text/html; charset=US-ASCII">
|
|
<title>Integrating Fibers with Asynchronous Callbacks</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="../index.html" title="Chapter 1. Fiber">
|
|
<link rel="prev" href="fls.html" title="Fiber local storage">
|
|
<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="fls.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>
|
|
</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">// We can confidently bind a reference to local variable 'promise' into</span>
|
|
<span class="comment">// the lambda callback because we know for a fact we're going to suspend</span>
|
|
<span class="comment">// (preserving the lifespan of both 'promise' and 'future') until the</span>
|
|
<span class="comment">// callback has fired.</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="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="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="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="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">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 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. The underlying implementation
|
|
uses the same mechanism as described above.
|
|
</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 such a completion token. <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="comment">/// A special value, similar to std::nothrow.</span>
|
|
<span class="identifier">BOOST_CONSTEXPR_OR_CONST</span> <span class="identifier">yield_t</span><span class="special"><></span> <span class="identifier">yield</span><span class="special">;</span>
|
|
</pre>
|
|
<p>
|
|
</p>
|
|
<p>
|
|
which is a <code class="computeroutput"><span class="identifier">promise_completion_token</span></code>:
|
|
</p>
|
|
<p>
|
|
</p>
|
|
<pre class="programlisting"><span class="keyword">template</span><span class="special"><</span> <span class="keyword">typename</span> <span class="identifier">Allocator</span> <span class="special">=</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">allocator</span><span class="special"><</span> <span class="keyword">void</span> <span class="special">></span> <span class="special">></span>
|
|
<span class="keyword">class</span> <span class="identifier">yield_t</span> <span class="special">:</span> <span class="keyword">public</span> <span class="identifier">promise_completion_token</span><span class="special"><</span> <span class="identifier">Allocator</span> <span class="special">></span> <span class="special">{</span>
|
|
<span class="keyword">public</span><span class="special">:</span>
|
|
<span class="comment">/// Construct with default-constructed allocator.</span>
|
|
<span class="identifier">BOOST_CONSTEXPR</span> <span class="identifier">yield_t</span><span class="special">()</span> <span class="special">{</span>
|
|
<span class="special">}</span>
|
|
<span class="comment">// ... ways to use an alternate allocator or bind an error_code ...</span>
|
|
<span class="special">};</span>
|
|
</pre>
|
|
<p>
|
|
</p>
|
|
<p>
|
|
<code class="computeroutput"><span class="identifier">promise_completion_token</span></code> is
|
|
common to both <code class="computeroutput"><span class="identifier">yield</span></code> and <code class="computeroutput"><span class="identifier">use_future</span></code>. (The interested reader is encouraged
|
|
to learn more about <code class="computeroutput"><span class="identifier">use_future</span></code>
|
|
in <a href="../../../examples/asio/use_future.hpp" target="_top">example source code</a>.)
|
|
</p>
|
|
<p>
|
|
<code class="computeroutput"><span class="identifier">promise_completion_token</span></code> is
|
|
in fact only a placeholder, a way to trigger Boost.Asio customization. It can
|
|
bind a custom allocator or <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>
|
|
</p>
|
|
<pre class="programlisting"><span class="keyword">template</span><span class="special"><</span> <span class="keyword">typename</span> <span class="identifier">Allocator</span> <span class="special">></span>
|
|
<span class="keyword">class</span> <span class="identifier">promise_completion_token</span> <span class="special">{</span>
|
|
<span class="keyword">public</span><span class="special">:</span>
|
|
<span class="keyword">typedef</span> <span class="identifier">Allocator</span> <span class="identifier">allocator_type</span><span class="special">;</span>
|
|
|
|
<span class="comment">/// Construct using default-constructed allocator.</span>
|
|
<span class="identifier">BOOST_CONSTEXPR</span> <span class="identifier">promise_completion_token</span><span class="special">()</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>
|
|
<span class="special">}</span>
|
|
|
|
<span class="comment">/// Construct using specified allocator.</span>
|
|
<span class="keyword">explicit</span> <span class="identifier">promise_completion_token</span><span class="special">(</span> <span class="identifier">Allocator</span> <span class="keyword">const</span><span class="special">&</span> <span class="identifier">allocator</span><span class="special">)</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="identifier">allocator_</span><span class="special">(</span> <span class="identifier">allocator</span><span class="special">)</span> <span class="special">{</span>
|
|
<span class="special">}</span>
|
|
|
|
<span class="comment">/// Obtain allocator.</span>
|
|
<span class="identifier">allocator_type</span> <span class="identifier">get_allocator</span><span class="special">()</span> <span class="keyword">const</span> <span class="special">{</span>
|
|
<span class="keyword">return</span> <span class="identifier">allocator_</span><span class="special">;</span>
|
|
<span class="special">}</span>
|
|
|
|
<span class="comment">//private:</span>
|
|
<span class="comment">// used by some subclasses to bind an error_code to suppress exceptions</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">private</span><span class="special">:</span>
|
|
<span class="identifier">Allocator</span> <span class="identifier">allocator_</span><span class="special">;</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="keyword">template</span><span class="special"><</span> <span class="keyword">typename</span> <span class="identifier">Allocator</span><span class="special">,</span> <span class="keyword">typename</span> <span class="identifier">ReturnType</span><span class="special">,</span> <span class="keyword">typename</span> <span class="identifier">Arg2</span> <span class="special">></span>
|
|
<span class="keyword">struct</span> <span class="identifier">handler_type</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">yield_t</span><span class="special"><</span> <span class="identifier">Allocator</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="identifier">Arg2</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="identifier">Arg2</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.
|
|
</p>
|
|
<p>
|
|
<code class="computeroutput"><span class="identifier">yield_handler</span></code> is simply an
|
|
alias for <code class="computeroutput"><span class="identifier">promise_handler</span></code>,
|
|
because <code class="computeroutput"><span class="identifier">promise_handler</span></code> is
|
|
shared with the <code class="computeroutput"><span class="identifier">use_future</span></code>
|
|
machinery:
|
|
</p>
|
|
<p>
|
|
</p>
|
|
<pre class="programlisting"><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">using</span> <span class="identifier">yield_handler</span> <span class="special">=</span> <span class="identifier">promise_handler</span><span class="special"><</span> <span class="identifier">T</span> <span class="special">>;</span>
|
|
</pre>
|
|
<p>
|
|
</p>
|
|
<p>
|
|
<code class="computeroutput"><span class="identifier">promise_handler</span></code> isa <code class="computeroutput"><span class="identifier">promise_handler_base</span></code>:
|
|
</p>
|
|
<p>
|
|
</p>
|
|
<pre class="programlisting"><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">promise_handler_base</span> <span class="special">{</span>
|
|
<span class="keyword">public</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">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">T</span> <span class="special">></span> <span class="special">></span> <span class="identifier">promise_ptr</span><span class="special">;</span>
|
|
|
|
<span class="comment">// Construct from any promise_completion_token subclass special value.</span>
|
|
<span class="keyword">template</span><span class="special"><</span> <span class="keyword">typename</span> <span class="identifier">Allocator</span> <span class="special">></span>
|
|
<span class="identifier">promise_handler_base</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">promise_completion_token</span><span class="special"><</span> <span class="identifier">Allocator</span> <span class="special">></span> <span class="keyword">const</span><span class="special">&</span> <span class="identifier">pct</span><span class="special">)</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">make_shared</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">T</span> <span class="special">></span> <span class="special">>(</span>
|
|
<span class="identifier">std</span><span class="special">::</span><span class="identifier">allocator_arg</span><span class="special">,</span> <span class="identifier">pct</span><span class="special">.</span><span class="identifier">get_allocator</span><span class="special">()</span> <span class="special">)</span> <span class="special">)</span>
|
|
<span class="special">{}</span>
|
|
|
|
<span class="keyword">bool</span> <span class="identifier">should_set_value</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="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="comment">// whew, success</span>
|
|
<span class="keyword">return</span> <span class="keyword">true</span><span class="special">;</span>
|
|
<span class="special">}</span>
|
|
|
|
<span class="comment">// no bound error_code: cause promise_ to throw an exception</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">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="comment">// caller should NOT call set_value()</span>
|
|
<span class="keyword">return</span> <span class="keyword">false</span><span class="special">;</span>
|
|
<span class="special">}</span>
|
|
|
|
<span class="identifier">promise_ptr</span> <span class="identifier">get_promise</span><span class="special">()</span> <span class="keyword">const</span> <span class="special">{</span>
|
|
<span class="keyword">return</span> <span class="identifier">promise_</span><span class="special">;</span>
|
|
<span class="special">}</span>
|
|
|
|
<span class="keyword">private</span><span class="special">:</span>
|
|
<span class="identifier">promise_ptr</span> <span class="identifier">promise_</span><span class="special">;</span>
|
|
<span class="special">};</span>
|
|
</pre>
|
|
<p>
|
|
</p>
|
|
<p>
|
|
As promised, <code class="computeroutput"><span class="identifier">promise_handler_base</span></code>
|
|
binds a <a class="link" href="synchronization/futures/promise.html#class_promise"> <code class="computeroutput">promise<></code></a> of appropriate type. (We store a <code class="computeroutput"><span class="identifier">shared_ptr</span><span class="special"><</span>
|
|
<span class="identifier">promise</span><span class="special"><</span>
|
|
<span class="identifier">T</span> <span class="special">></span>
|
|
<span class="special">></span></code> because the <code class="computeroutput"><span class="identifier">promise_handler</span></code>
|
|
instance is copied on its way into underlying Asio machinery.)
|
|
</p>
|
|
<p>
|
|
Asio, 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></code> (aka <code class="computeroutput"><span class="identifier">promise_handler</span></code>) as the async operation's
|
|
callback:
|
|
</p>
|
|
<p>
|
|
</p>
|
|
<pre class="programlisting"><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">promise_handler</span> <span class="special">:</span> <span class="keyword">public</span> <span class="identifier">promise_handler_base</span><span class="special"><</span> <span class="identifier">T</span> <span class="special">></span> <span class="special">{</span>
|
|
<span class="keyword">private</span><span class="special">:</span>
|
|
<span class="keyword">public</span><span class="special">:</span>
|
|
<span class="comment">// Construct from any promise_completion_token subclass special value.</span>
|
|
<span class="keyword">template</span><span class="special"><</span> <span class="keyword">typename</span> <span class="identifier">Allocator</span> <span class="special">></span>
|
|
<span class="identifier">promise_handler</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">promise_completion_token</span><span class="special"><</span> <span class="identifier">Allocator</span> <span class="special">></span> <span class="keyword">const</span><span class="special">&</span> <span class="identifier">pct</span><span class="special">)</span> <span class="special">:</span>
|
|
<span class="identifier">promise_handler_base</span><span class="special"><</span> <span class="identifier">T</span> <span class="special">>(</span> <span class="identifier">pct</span><span class="special">)</span> <span class="special">{</span>
|
|
<span class="special">}</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="keyword">if</span> <span class="special">(</span> <span class="identifier">should_set_value</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">get_promise</span><span class="special">()-></span><span class="identifier">set_value</span><span class="special">(</span> <span class="identifier">t</span><span class="special">);</span>
|
|
<span class="special">}</span>
|
|
<span class="special">}</span>
|
|
<span class="special">};</span>
|
|
</pre>
|
|
<p>
|
|
</p>
|
|
<p>
|
|
Like the lambda callback in our <a class="link" href="callbacks.html#Data_or_Exception"><code class="computeroutput"><span class="identifier">read</span><span class="special">(</span><span class="identifier">AsyncAPI</span><span class="special">&)</span></code></a> presented earlier, <code class="computeroutput"><span class="identifier">promise_handler</span><span class="special">::</span><span class="keyword">operator</span><span class="special">()()</span></code>
|
|
either calls <a class="link" href="synchronization/futures/promise.html#promise_set_value"> <code class="computeroutput">promise::set_value()</code></a> or <a class="link" href="synchronization/futures/promise.html#promise_set_exception"> <code class="computeroutput">promise::set_exception()</code></a> (via
|
|
<code class="computeroutput"><span class="identifier">promise_handler_base</span><span class="special">::</span><span class="identifier">should_set_value</span><span class="special">()</span></code>).
|
|
</p>
|
|
<p>
|
|
The source code above is found in <a href="../../../examples/asio/yield.hpp" target="_top">yield.hpp</a>,
|
|
<a href="../../../examples/asio/promise_completion_token.hpp" target="_top">promise_completion_token.hpp</a>,
|
|
<a href="../../../examples/asio/detail/yield.hpp" target="_top">detail/yield.hpp</a>
|
|
and <a href="../../../examples/asio/detail/promise_handler.hpp" target="_top">detail/promise_handler.hpp</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="fls.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>
|
|
</div>
|
|
</body>
|
|
</html>
|