1<html> 2<head> 3<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> 4<title>Timer.5 - Synchronising handlers in multithreaded programs</title> 5<link rel="stylesheet" href="../../../../doc/src/boostbook.css" type="text/css"> 6<meta name="generator" content="DocBook XSL Stylesheets V1.79.1"> 7<link rel="home" href="../../boost_asio.html" title="Boost.Asio"> 8<link rel="up" href="../tutorial.html" title="Tutorial"> 9<link rel="prev" href="tuttimer4/src.html" title="Source listing for Timer.4"> 10<link rel="next" href="tuttimer5/src.html" title="Source listing for Timer.5"> 11</head> 12<body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"> 13<table cellpadding="2" width="100%"><tr> 14<td valign="top"><img alt="Boost C++ Libraries" width="277" height="86" src="../../../../boost.png"></td> 15<td align="center"><a href="../../../../index.html">Home</a></td> 16<td align="center"><a href="../../../../libs/libraries.htm">Libraries</a></td> 17<td align="center"><a href="http://www.boost.org/users/people.html">People</a></td> 18<td align="center"><a href="http://www.boost.org/users/faq.html">FAQ</a></td> 19<td align="center"><a href="../../../../more/index.htm">More</a></td> 20</tr></table> 21<hr> 22<div class="spirit-nav"> 23<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> 24</div> 25<div class="section"> 26<div class="titlepage"><div><div><h3 class="title"> 27<a name="boost_asio.tutorial.tuttimer5"></a><a class="link" href="tuttimer5.html" title="Timer.5 - Synchronising handlers in multithreaded programs">Timer.5 - Synchronising 28 handlers in multithreaded programs</a> 29</h3></div></div></div> 30<p> 31 This tutorial demonstrates the use of the <a class="link" href="../reference/strand.html" title="strand">strand</a> 32 class template to synchronise callback handlers in a multithreaded program. 33 </p> 34<p> 35 The previous four tutorials avoided the issue of handler synchronisation 36 by calling the <a class="link" href="../reference/io_context/run.html" title="io_context::run">io_context::run()</a> 37 function from one thread only. As you already know, the asio library provides 38 a guarantee that callback handlers will only be called from threads that 39 are currently calling <a class="link" href="../reference/io_context/run.html" title="io_context::run">io_context::run()</a>. 40 Consequently, calling <a class="link" href="../reference/io_context/run.html" title="io_context::run">io_context::run()</a> 41 from only one thread ensures that callback handlers cannot run concurrently. 42 </p> 43<p> 44 The single threaded approach is usually the best place to start when developing 45 applications using asio. The downside is the limitations it places on programs, 46 particularly servers, including: 47 </p> 48<div class="itemizedlist"><ul class="itemizedlist" style="list-style-type: disc; "> 49<li class="listitem"> 50 Poor responsiveness when handlers can take a long time to complete. 51 </li> 52<li class="listitem"> 53 An inability to scale on multiprocessor systems. 54 </li> 55</ul></div> 56<p> 57 If you find yourself running into these limitations, an alternative approach 58 is to have a pool of threads calling <a class="link" href="../reference/io_context/run.html" title="io_context::run">io_context::run()</a>. 59 However, as this allows handlers to execute concurrently, we need a method 60 of synchronisation when handlers might be accessing a shared, thread-unsafe 61 resource. 62 </p> 63<pre class="programlisting">#include <iostream> 64#include <boost/asio.hpp> 65#include <boost/thread/thread.hpp> 66#include <boost/bind/bind.hpp> 67</pre> 68<p> 69 We start by defining a class called <code class="computeroutput">printer</code>, similar to the 70 class in the previous tutorial. This class will extend the previous tutorial 71 by running two timers in parallel. 72 </p> 73<pre class="programlisting">class printer 74{ 75public: 76</pre> 77<p> 78 In addition to initialising a pair of boost::asio::steady_timer members, 79 the constructor initialises the <code class="computeroutput">strand_</code> member, an object of 80 type boost::asio::strand<boost::asio::io_context::executor_type>. 81 </p> 82<p> 83 The <a class="link" href="../reference/strand.html" title="strand">strand</a> class template 84 is an executor adapter that guarantees that, for those handlers that are 85 dispatched through it, an executing handler will be allowed to complete before 86 the next one is started. This is guaranteed irrespective of the number of 87 threads that are calling <a class="link" href="../reference/io_context/run.html" title="io_context::run">io_context::run()</a>. 88 Of course, the handlers may still execute concurrently with other handlers 89 that were not dispatched through an <a class="link" href="../reference/strand.html" title="strand">strand</a>, 90 or were dispatched through a different <a class="link" href="../reference/strand.html" title="strand">strand</a> 91 object. 92 </p> 93<pre class="programlisting"> printer(boost::asio::io_context& io) 94 : strand_(boost::asio::make_strand(io)), 95 timer1_(io, boost::asio::chrono::seconds(1)), 96 timer2_(io, boost::asio::chrono::seconds(1)), 97 count_(0) 98 { 99</pre> 100<p> 101 When initiating the asynchronous operations, each callback handler is "bound" 102 to an boost::asio::strand<boost::asio::io_context::executor_type> object. 103 The boost::asio::bind_executor() function returns a new handler that automatically 104 dispatches its contained handler through the <a class="link" href="../reference/strand.html" title="strand">strand</a> 105 object. By binding the handlers to the same <a class="link" href="../reference/strand.html" title="strand">strand</a>, 106 we are ensuring that they cannot execute concurrently. 107 </p> 108<pre class="programlisting"> timer1_.async_wait(boost::asio::bind_executor(strand_, 109 boost::bind(&printer::print1, this))); 110 111 timer2_.async_wait(boost::asio::bind_executor(strand_, 112 boost::bind(&printer::print2, this))); 113 } 114 115 ~printer() 116 { 117 std::cout << "Final count is " << count_ << std::endl; 118 } 119</pre> 120<p> 121 In a multithreaded program, the handlers for asynchronous operations should 122 be synchronised if they access shared resources. In this tutorial, the shared 123 resources used by the handlers (<code class="computeroutput">print1</code> and <code class="computeroutput">print2</code>) 124 are <code class="computeroutput">std::cout</code> and the <code class="computeroutput">count_</code> data member. 125 </p> 126<pre class="programlisting"> void print1() 127 { 128 if (count_ < 10) 129 { 130 std::cout << "Timer 1: " << count_ << std::endl; 131 ++count_; 132 133 timer1_.expires_at(timer1_.expiry() + boost::asio::chrono::seconds(1)); 134 135 timer1_.async_wait(boost::asio::bind_executor(strand_, 136 boost::bind(&printer::print1, this))); 137 } 138 } 139 140 void print2() 141 { 142 if (count_ < 10) 143 { 144 std::cout << "Timer 2: " << count_ << std::endl; 145 ++count_; 146 147 timer2_.expires_at(timer2_.expiry() + boost::asio::chrono::seconds(1)); 148 149 timer2_.async_wait(boost::asio::bind_executor(strand_, 150 boost::bind(&printer::print2, this))); 151 } 152 } 153 154private: 155 boost::asio::strand<boost::asio::io_context::executor_type> strand_; 156 boost::asio::steady_timer timer1_; 157 boost::asio::steady_timer timer2_; 158 int count_; 159}; 160</pre> 161<p> 162 The <code class="computeroutput">main</code> function now causes <a class="link" href="../reference/io_context/run.html" title="io_context::run">io_context::run()</a> 163 to be called from two threads: the main thread and one additional thread. 164 This is accomplished using an boost::thread object. 165 </p> 166<p> 167 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_context::run()</a> will 168 continue to execute while there is "work" left to do. The background 169 thread will not exit until all asynchronous operations have completed. 170 </p> 171<pre class="programlisting">int main() 172{ 173 boost::asio::io_context io; 174 printer p(io); 175 boost::thread t(boost::bind(&boost::asio::io_context::run, &io)); 176 io.run(); 177 t.join(); 178 179 return 0; 180} 181</pre> 182<p> 183 See the <a class="link" href="tuttimer5/src.html" title="Source listing for Timer.5">full source listing</a> 184 </p> 185<p> 186 Return to the <a class="link" href="../tutorial.html" title="Tutorial">tutorial index</a> 187 </p> 188<p> 189 Previous: <a class="link" href="tuttimer4.html" title="Timer.4 - Using a member function as a handler">Timer.4 - Using a 190 member function as a handler</a> 191 </p> 192</div> 193<table xmlns:rev="http://www.cs.rpi.edu/~gregod/boost/tools/doc/revision" width="100%"><tr> 194<td align="left"></td> 195<td align="right"><div class="copyright-footer">Copyright © 2003-2020 Christopher M. 196 Kohlhoff<p> 197 Distributed under the Boost Software License, Version 1.0. (See accompanying 198 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>) 199 </p> 200</div></td> 201</tr></table> 202<hr> 203<div class="spirit-nav"> 204<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> 205</div> 206</body> 207</html> 208