summaryrefslogtreecommitdiff
path: root/doc/html/boost_asio/tutorial/tuttimer5.html
blob: be3dd761655ff482ead4523dec21107bd663c8d7 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=US-ASCII">
<title>Timer.5 - Synchronising handlers in multithreaded programs</title>
<link rel="stylesheet" href="../../../../doc/src/boostbook.css" type="text/css">
<meta name="generator" content="DocBook XSL Stylesheets V1.79.1">
<link rel="home" href="../../boost_asio.html" title="Boost.Asio">
<link rel="up" href="../tutorial.html" title="Tutorial">
<link rel="prev" href="tuttimer4/src.html" title="Source listing for Timer.4">
<link rel="next" href="tuttimer5/src.html" title="Source listing for Timer.5">
</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="tuttimer4/src.html"><img src="../../../../doc/src/images/prev.png" alt="Prev"></a><a accesskey="u" href="../tutorial.html"><img src="../../../../doc/src/images/up.png" alt="Up"></a><a accesskey="h" href="../../boost_asio.html"><img src="../../../../doc/src/images/home.png" alt="Home"></a><a accesskey="n" href="tuttimer5/src.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="boost_asio.tutorial.tuttimer5"></a><a class="link" href="tuttimer5.html" title="Timer.5 - Synchronising handlers in multithreaded programs">Timer.5 - Synchronising
      handlers in multithreaded programs</a>
</h3></div></div></div>
<p>
        This tutorial demonstrates the use of the boost::asio::io_service::strand
        class to synchronise callback handlers in a multithreaded program.
      </p>
<p>
        The previous four tutorials avoided the issue of handler synchronisation
        by calling the <a class="link" href="../reference/io_context/run.html" title="io_context::run">io_service::run()</a>
        function from one thread only. As you already know, the asio library provides
        a guarantee that callback handlers will only be called from threads that
        are currently calling <a class="link" href="../reference/io_context/run.html" title="io_context::run">io_service::run()</a>.
        Consequently, calling <a class="link" href="../reference/io_context/run.html" title="io_context::run">io_service::run()</a>
        from only one thread ensures that callback handlers cannot run concurrently.
      </p>
<p>
        The single threaded approach is usually the best place to start when developing
        applications using asio. The downside is the limitations it places on programs,
        particularly servers, including:
      </p>
<div class="itemizedlist"><ul class="itemizedlist" style="list-style-type: disc; ">
<li class="listitem">
            Poor responsiveness when handlers can take a long time to complete.
          </li>
<li class="listitem">
            An inability to scale on multiprocessor systems.
          </li>
</ul></div>
<p>
        If you find yourself running into these limitations, an alternative approach
        is to have a pool of threads calling <a class="link" href="../reference/io_context/run.html" title="io_context::run">io_service::run()</a>.
        However, as this allows handlers to execute concurrently, we need a method
        of synchronisation when handlers might be accessing a shared, thread-unsafe
        resource.
      </p>
<pre class="programlisting">#include &lt;iostream&gt;
#include &lt;boost/asio.hpp&gt;
#include &lt;boost/thread/thread.hpp&gt;
#include &lt;boost/bind.hpp&gt;
#include &lt;boost/date_time/posix_time/posix_time.hpp&gt;
</pre>
<p>
        We start by defining a class called <code class="computeroutput">printer</code>, similar to the
        class in the previous tutorial. This class will extend the previous tutorial
        by running two timers in parallel.
      </p>
<pre class="programlisting">class printer
{
public:
</pre>
<p>
        In addition to initialising a pair of boost::asio::deadline_timer members,
        the constructor initialises the <code class="computeroutput">strand_</code> member, an object of
        type boost::asio::io_service::strand.
      </p>
<p>
        An boost::asio::io_service::strand is an executor that guarantees that, for
        those handlers that are dispatched through it, an executing handler will
        be allowed to complete before the next one is started. This is guaranteed
        irrespective of the number of threads that are calling <a class="link" href="../reference/io_context/run.html" title="io_context::run">io_service::run()</a>.
        Of course, the handlers may still execute concurrently with other handlers
        that were not dispatched through an boost::asio::io_service::strand, or were
        dispatched through a different boost::asio::io_service::strand object.
      </p>
<pre class="programlisting">  printer(boost::asio::io_context&amp; io)
    : strand_(io),
      timer1_(io, boost::posix_time::seconds(1)),
      timer2_(io, boost::posix_time::seconds(1)),
      count_(0)
  {
</pre>
<p>
        When initiating the asynchronous operations, each callback handler is "bound"
        to an boost::asio::io_service::strand object. The boost::asio::io_service::strand::bind_executor()
        function returns a new handler that automatically dispatches its contained
        handler through the boost::asio::io_service::strand object. By binding the
        handlers to the same boost::asio::io_service::strand, we are ensuring that
        they cannot execute concurrently.
      </p>
<pre class="programlisting">    timer1_.async_wait(boost::asio::bind_executor(strand_,
          boost::bind(&amp;printer::print1, this)));

    timer2_.async_wait(boost::asio::bind_executor(strand_,
          boost::bind(&amp;printer::print2, this)));
  }

  ~printer()
  {
    std::cout &lt;&lt; "Final count is " &lt;&lt; count_ &lt;&lt; std::endl;
  }
</pre>
<p>
        In a multithreaded program, the handlers for asynchronous operations should
        be synchronised if they access shared resources. In this tutorial, the shared
        resources used by the handlers (<code class="computeroutput">print1</code> and <code class="computeroutput">print2</code>)
        are <code class="computeroutput">std::cout</code> and the <code class="computeroutput">count_</code> data member.
      </p>
<pre class="programlisting">  void print1()
  {
    if (count_ &lt; 10)
    {
      std::cout &lt;&lt; "Timer 1: " &lt;&lt; count_ &lt;&lt; std::endl;
      ++count_;

      timer1_.expires_at(timer1_.expires_at() + boost::posix_time::seconds(1));

      timer1_.async_wait(boost::asio::bind_executor(strand_,
            boost::bind(&amp;printer::print1, this)));
    }
  }

  void print2()
  {
    if (count_ &lt; 10)
    {
      std::cout &lt;&lt; "Timer 2: " &lt;&lt; count_ &lt;&lt; std::endl;
      ++count_;

      timer2_.expires_at(timer2_.expires_at() + boost::posix_time::seconds(1));

      timer2_.async_wait(boost::asio::bind_executor(strand_,
            boost::bind(&amp;printer::print2, this)));
    }
  }

private:
  boost::asio::io_context::strand strand_;
  boost::asio::deadline_timer timer1_;
  boost::asio::deadline_timer timer2_;
  int count_;
};
</pre>
<p>
        The <code class="computeroutput">main</code> function now causes <a class="link" href="../reference/io_context/run.html" title="io_context::run">io_service::run()</a>
        to be called from two threads: the main thread and one additional thread.
        This is accomplished using an boost::thread object.
      </p>
<p>
        Just as it would with a call from a single thread, concurrent calls to <a class="link" href="../reference/io_context/run.html" title="io_context::run">io_service::run()</a> will
        continue to execute while there is "work" left to do. The background
        thread will not exit until all asynchronous operations have completed.
      </p>
<pre class="programlisting">int main()
{
  boost::asio::io_context io;
  printer p(io);
  boost::thread t(boost::bind(&amp;boost::asio::io_context::run, &amp;io));
  io.run();
  t.join();

  return 0;
}
</pre>
<p>
        See the <a class="link" href="tuttimer5/src.html" title="Source listing for Timer.5">full source listing</a>
      </p>
<p>
        Return to the <a class="link" href="../tutorial.html" title="Tutorial">tutorial index</a>
      </p>
<p>
        Previous: <a class="link" href="tuttimer4.html" title="Timer.4 - Using a member function as a handler">Timer.4 - Using a
        member function as a handler</a>
      </p>
</div>
<table xmlns:rev="http://www.cs.rpi.edu/~gregod/boost/tools/doc/revision" width="100%"><tr>
<td align="left"></td>
<td align="right"><div class="copyright-footer">Copyright &#169; 2003-2017 Christopher M. Kohlhoff<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="tuttimer4/src.html"><img src="../../../../doc/src/images/prev.png" alt="Prev"></a><a accesskey="u" href="../tutorial.html"><img src="../../../../doc/src/images/up.png" alt="Up"></a><a accesskey="h" href="../../boost_asio.html"><img src="../../../../doc/src/images/home.png" alt="Home"></a><a accesskey="n" href="tuttimer5/src.html"><img src="../../../../doc/src/images/next.png" alt="Next"></a>
</div>
</body>
</html>