~ubuntu-branches/ubuntu/jaunty/asio/jaunty

« back to all changes in this revision

Viewing changes to doc/tutorial/tuttimer5.html

  • Committer: Bazaar Package Importer
  • Author(s): Simon Richter
  • Date: 2007-09-07 11:10:41 UTC
  • Revision ID: james.westby@ubuntu.com-20070907111041-f0uwhs0llvzj9ah5
Tags: upstream-0.3.8~rc3
ImportĀ upstreamĀ versionĀ 0.3.8~rc3

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
<HTML>
 
2
  <HEAD>
 
3
    <TITLE>asio Tutorial: Timer.5 - Synchronising handlers in multithreaded programs</TITLE>
 
4
    <LINK HREF="asio.css" REL="stylesheet" TYPE="text/css">
 
5
    <LINK HREF="tabs.css" REL="stylesheet" TYPE="text/css">
 
6
  </HEAD>
 
7
  <BODY BGCOLOR="#FFFFFF">
 
8
    <DIV CLASS="qindex">
 
9
      <TABLE BORDER="0" WIDTH="100%">
 
10
        <TR>
 
11
          <TD ALIGN="LEFT">
 
12
            <B>asio 0.3.8rc3</B>
 
13
          </TD>
 
14
          <TD ALIGN="RIGHT">
 
15
            <A CLASS="qindex" HREF="../index.html">Home</A> |
 
16
            <A CLASS="qindex" HREF="../reference/index.html">Reference</A> |
 
17
            <A CLASS="qindex" HREF="../tutorial/index.html">Tutorial</A> |
 
18
            <A CLASS="qindex" HREF="../examples/index.html">Examples</A> |
 
19
            <A CLASS="qindex" HREF="../design/index.html">Design</A>
 
20
          </TD>
 
21
        </TR>
 
22
      </TABLE>
 
23
    </DIV>
 
24
    <DIV CLASS="qindex">
 
25
      <TABLE BORDER="0" WIDTH="100%">
 
26
        <TR>
 
27
          <TD ALIGN="LEFT">
 
28
            <B>Tutorial</B>
 
29
          </TD>
 
30
        </TR>
 
31
      </TABLE>
 
32
    </DIV>
 
33
<!-- Generated by Doxygen 1.5.1 -->
 
34
<h1><a class="anchor" name="tuttimer5">Timer.5 - Synchronising handlers in multithreaded programs</a></h1>This tutorial demonstrates the use of the <a class="elRef" doxygen="asio.doxytags:../reference/" href="../reference/a00126.html#3be3fa00c86ab58ba41aabe8fcbf11be">asio::strand</a> class to synchronise callback handlers in a multithreaded program.<p>
 
35
The previous four tutorials avoided the issue of handler synchronisation by calling the <a class="elRef" doxygen="asio.doxytags:../reference/" href="../reference/a00032.html#c84bed0d1dd061bc71010ba1228439da">asio::io_service::run()</a> function from one thread only. As you already know, the asio library provides a guarantee that callback handlers will <b>only</b> be called from threads that are currently calling <a class="elRef" doxygen="asio.doxytags:../reference/" href="../reference/a00032.html#c84bed0d1dd061bc71010ba1228439da">asio::io_service::run()</a>. Consequently, calling <a class="elRef" doxygen="asio.doxytags:../reference/" href="../reference/a00032.html#c84bed0d1dd061bc71010ba1228439da">asio::io_service::run()</a> from only one thread ensures that callback handlers cannot run concurrently.<p>
 
36
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>
 
37
<ul>
 
38
<li>
 
39
Poor responsiveness when handlers can take a long time to complete. </li>
 
40
<li>
 
41
An inability to scale on multiprocessor systems. </li>
 
42
</ul>
 
43
<p>
 
44
If you find yourself running into these limitations, an alternative approach is to have a pool of threads calling <a class="elRef" doxygen="asio.doxytags:../reference/" href="../reference/a00032.html#c84bed0d1dd061bc71010ba1228439da">asio::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>
 
45
 <div class="fragment"><pre class="fragment"></pre></div><p>
 
46
<div class="fragment"><pre class="fragment"><span class="preprocessor">#include &lt;iostream&gt;</span>
 
47
<span class="preprocessor">#include &lt;asio.hpp&gt;</span>
 
48
<span class="preprocessor">#include &lt;boost/bind.hpp&gt;</span>
 
49
<span class="preprocessor">#include &lt;boost/date_time/posix_time/posix_time.hpp&gt;</span>
 
50
</pre></div><p>
 
51
We start by defining a class called <code>printer</code>, similar to the class in the previous tutorial. This class will extend the previous tutorial by running two timers in parallel.<p>
 
52
<div class="fragment"><pre class="fragment">
 
53
<span class="keyword">class </span>printer
 
54
{
 
55
<span class="keyword">public</span>:
 
56
</pre></div><p>
 
57
In addition to initialising a pair of <a class="elRef" doxygen="asio.doxytags:../reference/" href="../reference/a00126.html#9c1e57628983c6b9c45e9204228109b7">asio::deadline_timer</a> members, the constructor initialises the <code>strand_</code> member, an object of type <a class="elRef" doxygen="asio.doxytags:../reference/" href="../reference/a00126.html#3be3fa00c86ab58ba41aabe8fcbf11be">asio::strand</a>.<p>
 
58
An <a class="elRef" doxygen="asio.doxytags:../reference/" href="../reference/a00126.html#3be3fa00c86ab58ba41aabe8fcbf11be">asio::strand</a> 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="elRef" doxygen="asio.doxytags:../reference/" href="../reference/a00032.html#c84bed0d1dd061bc71010ba1228439da">asio::io_service::run()</a>. Of course, the handlers may still execute concurrently with other handlers that were <b>not</b> dispatched through an <a class="elRef" doxygen="asio.doxytags:../reference/" href="../reference/a00126.html#3be3fa00c86ab58ba41aabe8fcbf11be">asio::strand</a>, or were dispatched through a different <a class="elRef" doxygen="asio.doxytags:../reference/" href="../reference/a00126.html#3be3fa00c86ab58ba41aabe8fcbf11be">asio::strand</a> object.<p>
 
59
<div class="fragment"><pre class="fragment">  printer(<a class="codeRef" doxygen="asio.doxytags:../reference/" href="../reference/a00032.html">asio::io_service</a>&amp; io)
 
60
    : strand_(io),
 
61
      timer1_(io, boost::posix_time::seconds(1)),
 
62
      timer2_(io, boost::posix_time::seconds(1)),
 
63
      count_(0)
 
64
  {
 
65
</pre></div><p>
 
66
When initiating the asynchronous operations, each callback handler is "wrapped" using the <a class="elRef" doxygen="asio.doxytags:../reference/" href="../reference/a00126.html#3be3fa00c86ab58ba41aabe8fcbf11be">asio::strand</a> object. The <a class="elRef" doxygen="asio.doxytags:../reference/" href="../reference/a00035.html#ebaeb20a72830b4c6f4552fb30bff742">asio::strand::wrap()</a> function returns a new handler that automatically dispatches its contained handler through the <a class="elRef" doxygen="asio.doxytags:../reference/" href="../reference/a00126.html#3be3fa00c86ab58ba41aabe8fcbf11be">asio::strand</a> object. By wrapping the handlers using the same <a class="elRef" doxygen="asio.doxytags:../reference/" href="../reference/a00126.html#3be3fa00c86ab58ba41aabe8fcbf11be">asio::strand</a>, we are ensuring that they cannot execute concurrently.<p>
 
67
<div class="fragment"><pre class="fragment">    timer1_.async_wait(strand_.wrap(boost::bind(&amp;printer::print1, <span class="keyword">this</span>)));
 
68
    timer2_.async_wait(strand_.wrap(boost::bind(&amp;printer::print2, <span class="keyword">this</span>)));
 
69
  }
 
70
 
 
71
  ~printer()
 
72
  {
 
73
    std::cout &lt;&lt; <span class="stringliteral">"Final count is "</span> &lt;&lt; count_ &lt;&lt; <span class="stringliteral">"\n"</span>;
 
74
  }
 
75
</pre></div><p>
 
76
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>print1</code> and <code>print2</code>) are <code>std::cout</code> and the <code>count_</code> data member.<p>
 
77
<div class="fragment"><pre class="fragment">
 
78
  <span class="keywordtype">void</span> print1()
 
79
  {
 
80
    <span class="keywordflow">if</span> (count_ &lt; 10)
 
81
    {
 
82
      std::cout &lt;&lt; <span class="stringliteral">"Timer 1: "</span> &lt;&lt; count_ &lt;&lt; <span class="stringliteral">"\n"</span>;
 
83
      ++count_;
 
84
 
 
85
      timer1_.expires_at(timer1_.expires_at() + boost::posix_time::seconds(1));
 
86
      timer1_.async_wait(strand_.wrap(boost::bind(&amp;printer::print1, <span class="keyword">this</span>)));
 
87
    }
 
88
  }
 
89
 
 
90
  <span class="keywordtype">void</span> print2()
 
91
  {
 
92
    <span class="keywordflow">if</span> (count_ &lt; 10)
 
93
    {
 
94
      std::cout &lt;&lt; <span class="stringliteral">"Timer 2: "</span> &lt;&lt; count_ &lt;&lt; <span class="stringliteral">"\n"</span>;
 
95
      ++count_;
 
96
 
 
97
      timer2_.expires_at(timer2_.expires_at() + boost::posix_time::seconds(1));
 
98
      timer2_.async_wait(strand_.wrap(boost::bind(&amp;printer::print2, <span class="keyword">this</span>)));
 
99
    }
 
100
  }
 
101
 
 
102
<span class="keyword">private</span>:
 
103
  <a class="codeRef" doxygen="asio.doxytags:../reference/" href="../reference/a00035.html">asio::strand</a> strand_;
 
104
  <a class="codeRef" doxygen="asio.doxytags:../reference/" href="../reference/a00006.html">asio::deadline_timer</a> timer1_;
 
105
  <a class="codeRef" doxygen="asio.doxytags:../reference/" href="../reference/a00006.html">asio::deadline_timer</a> timer2_;
 
106
  <span class="keywordtype">int</span> count_;
 
107
};
 
108
</pre></div><p>
 
109
The <code>main</code> function now causes <a class="elRef" doxygen="asio.doxytags:../reference/" href="../reference/a00032.html#c84bed0d1dd061bc71010ba1228439da">asio::io_service::run()</a> to be called from two threads: the main thread and one additional thread. This is accomplished using an <a class="elRef" doxygen="asio.doxytags:../reference/" href="../reference/a00052.html">asio::thread</a> object.<p>
 
110
Just as it would with a call from a single thread, concurrent calls to <a class="elRef" doxygen="asio.doxytags:../reference/" href="../reference/a00032.html#c84bed0d1dd061bc71010ba1228439da">asio::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>
 
111
<div class="fragment"><pre class="fragment">
 
112
<span class="keywordtype">int</span> main()
 
113
{
 
114
  <a class="codeRef" doxygen="asio.doxytags:../reference/" href="../reference/a00032.html">asio::io_service</a> io;
 
115
  printer p(io);
 
116
  <a class="codeRef" doxygen="asio.doxytags:../reference/" href="../reference/a00052.html">asio::thread</a> t(boost::bind(&amp;<a class="codeRef" doxygen="asio.doxytags:../reference/" href="../reference/a00032.html#c84bed0d1dd061bc71010ba1228439da">asio::io_service::run</a>, &amp;io));
 
117
  io.<a class="codeRef" doxygen="asio.doxytags:../reference/" href="../reference/a00032.html#c84bed0d1dd061bc71010ba1228439da">run</a>();
 
118
  t.join();
 
119
 
 
120
  <span class="keywordflow">return</span> 0;
 
121
}
 
122
</pre></div><p>
 
123
See the <a class="el" href="tuttimer5src.html">full source listing</a> <br>
 
124
 Return to the <a class="el" href="index.html#index">tutorial index</a> <br>
 
125
 Previous: <a class="el" href="tuttimer4.html">Timer.4 - Using a member function as a handler</a> <br>
 
126
     <DIV CLASS="qindex">
 
127
      <TABLE BORDER="0" WIDTH="100%">
 
128
        <TR>
 
129
          <TD ALIGN="LEFT">
 
130
            <B>asio 0.3.8rc3</B>
 
131
          </TD>
 
132
          <TD ALIGN="RIGHT">
 
133
            <A CLASS="qindex" HREF="../index.html">Home</A> |
 
134
            <A CLASS="qindex" HREF="../reference/index.html">Reference</A> |
 
135
            <A CLASS="qindex" HREF="../tutorial/index.html">Tutorial</A> |
 
136
            <A CLASS="qindex" HREF="../examples/index.html">Examples</A> |
 
137
            <A CLASS="qindex" HREF="../design/index.html">Design</A>
 
138
          </TD>
 
139
        </TR>
 
140
      </TABLE>
 
141
    </DIV>
 
142
  </BODY>
 
143
</HTML>