| <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.75.2"> |
| <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::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_service/run.html" title="io_service::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_service/run.html" title="io_service::run">io_service::run()</a>. |
| Consequently, calling <a class="link" href="../reference/io_service/run.html" title="io_service::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" 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_service/run.html" title="io_service::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"><span class="preprocessor">#include</span> <span class="special"><</span><span class="identifier">iostream</span><span class="special">></span> |
| <span class="preprocessor">#include</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">hpp</span><span class="special">></span> |
| <span class="preprocessor">#include</span> <span class="special"><</span><span class="identifier">boost</span><span class="special">/</span><span class="identifier">thread</span><span class="special">.</span><span class="identifier">hpp</span><span class="special">></span> |
| <span class="preprocessor">#include</span> <span class="special"><</span><span class="identifier">boost</span><span class="special">/</span><span class="identifier">bind</span><span class="special">.</span><span class="identifier">hpp</span><span class="special">></span> |
| <span class="preprocessor">#include</span> <span class="special"><</span><span class="identifier">boost</span><span class="special">/</span><span class="identifier">date_time</span><span class="special">/</span><span class="identifier">posix_time</span><span class="special">/</span><span class="identifier">posix_time</span><span class="special">.</span><span class="identifier">hpp</span><span class="special">></span> |
| </pre> |
| <p> |
| We start by defining a class called <code class="computeroutput"><span class="identifier">printer</span></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"><span class="keyword">class</span> <span class="identifier">printer</span> |
| <span class="special">{</span> |
| <span class="keyword">public</span><span class="special">:</span> |
| </pre> |
| <p> |
| In addition to initialising a pair of boost::asio::deadline_timer members, |
| the constructor initialises the <code class="computeroutput"><span class="identifier">strand_</span></code> |
| member, an object of type boost::asio::strand. |
| </p> |
| <p> |
| An boost::asio::strand 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_service/run.html" title="io_service::run">io_service::run()</a>. |
| Of course, the handlers may still execute concurrently with other handlers |
| that were not dispatched through an boost::asio::strand, or were dispatched |
| through a different boost::asio::strand object. |
| </p> |
| <pre class="programlisting"> <span class="identifier">printer</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</span><span class="special">)</span> |
| <span class="special">:</span> <span class="identifier">strand_</span><span class="special">(</span><span class="identifier">io</span><span class="special">),</span> |
| <span class="identifier">timer1_</span><span class="special">(</span><span class="identifier">io</span><span class="special">,</span> <span class="identifier">boost</span><span class="special">::</span><span class="identifier">posix_time</span><span class="special">::</span><span class="identifier">seconds</span><span class="special">(</span><span class="number">1</span><span class="special">)),</span> |
| <span class="identifier">timer2_</span><span class="special">(</span><span class="identifier">io</span><span class="special">,</span> <span class="identifier">boost</span><span class="special">::</span><span class="identifier">posix_time</span><span class="special">::</span><span class="identifier">seconds</span><span class="special">(</span><span class="number">1</span><span class="special">)),</span> |
| <span class="identifier">count_</span><span class="special">(</span><span class="number">0</span><span class="special">)</span> |
| <span class="special">{</span> |
| </pre> |
| <p> |
| When initiating the asynchronous operations, each callback handler is "wrapped" |
| using the boost::asio::strand object. The <a class="link" href="../reference/io_service__strand/wrap.html" title="io_service::strand::wrap">strand::wrap()</a> |
| function returns a new handler that automatically dispatches its contained |
| handler through the boost::asio::strand object. By wrapping the handlers |
| using the same boost::asio::strand, we are ensuring that they cannot execute |
| concurrently. |
| </p> |
| <pre class="programlisting"> <span class="identifier">timer1_</span><span class="special">.</span><span class="identifier">async_wait</span><span class="special">(</span><span class="identifier">strand_</span><span class="special">.</span><span class="identifier">wrap</span><span class="special">(</span><span class="identifier">boost</span><span class="special">::</span><span class="identifier">bind</span><span class="special">(&</span><span class="identifier">printer</span><span class="special">::</span><span class="identifier">print1</span><span class="special">,</span> <span class="keyword">this</span><span class="special">)));</span> |
| <span class="identifier">timer2_</span><span class="special">.</span><span class="identifier">async_wait</span><span class="special">(</span><span class="identifier">strand_</span><span class="special">.</span><span class="identifier">wrap</span><span class="special">(</span><span class="identifier">boost</span><span class="special">::</span><span class="identifier">bind</span><span class="special">(&</span><span class="identifier">printer</span><span class="special">::</span><span class="identifier">print2</span><span class="special">,</span> <span class="keyword">this</span><span class="special">)));</span> |
| <span class="special">}</span> |
| |
| <span class="special">~</span><span class="identifier">printer</span><span class="special">()</span> |
| <span class="special">{</span> |
| <span class="identifier">std</span><span class="special">::</span><span class="identifier">cout</span> <span class="special"><<</span> <span class="string">"Final count is "</span> <span class="special"><<</span> <span class="identifier">count_</span> <span class="special"><<</span> <span class="string">"\n"</span><span class="special">;</span> |
| <span class="special">}</span> |
| </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"><span class="identifier">print1</span></code> |
| and <code class="computeroutput"><span class="identifier">print2</span></code>) are <code class="computeroutput"><span class="identifier">std</span><span class="special">::</span><span class="identifier">cout</span></code> |
| and the <code class="computeroutput"><span class="identifier">count_</span></code> data member. |
| </p> |
| <pre class="programlisting"> <span class="keyword">void</span> <span class="identifier">print1</span><span class="special">()</span> |
| <span class="special">{</span> |
| <span class="keyword">if</span> <span class="special">(</span><span class="identifier">count_</span> <span class="special"><</span> <span class="number">10</span><span class="special">)</span> |
| <span class="special">{</span> |
| <span class="identifier">std</span><span class="special">::</span><span class="identifier">cout</span> <span class="special"><<</span> <span class="string">"Timer 1: "</span> <span class="special"><<</span> <span class="identifier">count_</span> <span class="special"><<</span> <span class="string">"\n"</span><span class="special">;</span> |
| <span class="special">++</span><span class="identifier">count_</span><span class="special">;</span> |
| |
| <span class="identifier">timer1_</span><span class="special">.</span><span class="identifier">expires_at</span><span class="special">(</span><span class="identifier">timer1_</span><span class="special">.</span><span class="identifier">expires_at</span><span class="special">()</span> <span class="special">+</span> <span class="identifier">boost</span><span class="special">::</span><span class="identifier">posix_time</span><span class="special">::</span><span class="identifier">seconds</span><span class="special">(</span><span class="number">1</span><span class="special">));</span> |
| <span class="identifier">timer1_</span><span class="special">.</span><span class="identifier">async_wait</span><span class="special">(</span><span class="identifier">strand_</span><span class="special">.</span><span class="identifier">wrap</span><span class="special">(</span><span class="identifier">boost</span><span class="special">::</span><span class="identifier">bind</span><span class="special">(&</span><span class="identifier">printer</span><span class="special">::</span><span class="identifier">print1</span><span class="special">,</span> <span class="keyword">this</span><span class="special">)));</span> |
| <span class="special">}</span> |
| <span class="special">}</span> |
| |
| <span class="keyword">void</span> <span class="identifier">print2</span><span class="special">()</span> |
| <span class="special">{</span> |
| <span class="keyword">if</span> <span class="special">(</span><span class="identifier">count_</span> <span class="special"><</span> <span class="number">10</span><span class="special">)</span> |
| <span class="special">{</span> |
| <span class="identifier">std</span><span class="special">::</span><span class="identifier">cout</span> <span class="special"><<</span> <span class="string">"Timer 2: "</span> <span class="special"><<</span> <span class="identifier">count_</span> <span class="special"><<</span> <span class="string">"\n"</span><span class="special">;</span> |
| <span class="special">++</span><span class="identifier">count_</span><span class="special">;</span> |
| |
| <span class="identifier">timer2_</span><span class="special">.</span><span class="identifier">expires_at</span><span class="special">(</span><span class="identifier">timer2_</span><span class="special">.</span><span class="identifier">expires_at</span><span class="special">()</span> <span class="special">+</span> <span class="identifier">boost</span><span class="special">::</span><span class="identifier">posix_time</span><span class="special">::</span><span class="identifier">seconds</span><span class="special">(</span><span class="number">1</span><span class="special">));</span> |
| <span class="identifier">timer2_</span><span class="special">.</span><span class="identifier">async_wait</span><span class="special">(</span><span class="identifier">strand_</span><span class="special">.</span><span class="identifier">wrap</span><span class="special">(</span><span class="identifier">boost</span><span class="special">::</span><span class="identifier">bind</span><span class="special">(&</span><span class="identifier">printer</span><span class="special">::</span><span class="identifier">print2</span><span class="special">,</span> <span class="keyword">this</span><span class="special">)));</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">asio</span><span class="special">::</span><span class="identifier">strand</span> <span class="identifier">strand_</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">deadline_timer</span> <span class="identifier">timer1_</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">deadline_timer</span> <span class="identifier">timer2_</span><span class="special">;</span> |
| <span class="keyword">int</span> <span class="identifier">count_</span><span class="special">;</span> |
| <span class="special">};</span> |
| </pre> |
| <p> |
| The <code class="computeroutput"><span class="identifier">main</span></code> function now causes |
| <a class="link" href="../reference/io_service/run.html" title="io_service::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_service/run.html" title="io_service::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"><span class="keyword">int</span> <span class="identifier">main</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="identifier">io</span><span class="special">;</span> |
| <span class="identifier">printer</span> <span class="identifier">p</span><span class="special">(</span><span class="identifier">io</span><span class="special">);</span> |
| <span class="identifier">boost</span><span class="special">::</span><span class="identifier">thread</span> <span class="identifier">t</span><span class="special">(</span><span class="identifier">boost</span><span class="special">::</span><span class="identifier">bind</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">run</span><span class="special">,</span> <span class="special">&</span><span class="identifier">io</span><span class="special">));</span> |
| <span class="identifier">io</span><span class="special">.</span><span class="identifier">run</span><span class="special">();</span> |
| <span class="identifier">t</span><span class="special">.</span><span class="identifier">join</span><span class="special">();</span> |
| |
| <span class="keyword">return</span> <span class="number">0</span><span class="special">;</span> |
| <span class="special">}</span> |
| </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 © 2003 - 2010 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> |