2 // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com)
4 // Distributed under the Boost Software License, Version 1.0. (See accompanying
5 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
9 \page tuttimer1 Timer.1 - Using a timer synchronously
11 This tutorial program introduces asio by showing how to perform a blocking
14 \dontinclude timer1/timer.cpp
17 We start by including the necessary header files.
19 All of the asio classes can be used by simply including the <tt>"asio.hpp"</tt>
24 All programs that use asio need to have at least one I/O execution context,
25 such as an boost::asio::io_context or boost::asio::thread_pool object. An I/O execution
26 context provides access to I/O functionality. We declare an object of type
27 boost::asio::io_context first thing in the main function.
29 \until boost::asio::io_context
31 Next we declare an object of type boost::asio::steady_timer. The core asio classes
32 that provide I/O functionality (or as in this case timer functionality) always
33 take a reference to an io_context as their first constructor argument. The
34 second argument to the constructor sets the timer to expire 5 seconds from now.
36 \until boost::asio::steady_timer
38 In this simple example we perform a blocking wait on the timer.
39 That is, the call to boost::asio::steady_timer::wait() will not return until the
40 timer has expired, 5 seconds after it was created (i.e. <b>not</b> from when the
43 A timer is always in one of two states: "expired" or "not expired". If the
44 boost::asio::steady_timer::wait() function is called on an expired timer, it will
49 Finally we print the obligatory <tt>"Hello, world!"</tt>
50 message to show when the timer has expired.
54 See the \ref tuttimer1src "full source listing" \n
55 Return to the \ref index "tutorial index" \n
61 \page tuttimer1src Source listing for Timer.1
62 \include timer1/timer.cpp
63 Return to \ref tuttimer1
67 \page tuttimer2 Timer.2 - Using a timer asynchronously
69 This tutorial program demonstrates how to use asio's asynchronous callback
70 functionality by modifying the program from tutorial Timer.1 to perform an
71 asynchronous wait on the timer.
73 \dontinclude timer2/timer.cpp
78 Using asio's asynchronous functionality means having a callback
79 function that will be called when an asynchronous operation completes. In this
80 program we define a function called <tt>print</tt> to be called when the
81 asynchronous wait finishes.
83 \until boost::asio::steady_timer
85 Next, instead of doing a blocking wait as in tutorial Timer.1,
86 we call the boost::asio::steady_timer::async_wait() function to perform an
87 asynchronous wait. When calling this function we pass the <tt>print</tt>
88 callback handler that was defined above.
92 Finally, we must call the boost::asio::io_context::run() member function
93 on the io_context object.
95 The asio library provides a guarantee that callback handlers will <b>only</b>
96 be called from threads that are currently calling boost::asio::io_context::run().
97 Therefore unless the boost::asio::io_context::run() function is called the callback for
98 the asynchronous wait completion will never be invoked.
100 The boost::asio::io_context::run() function will also continue to run while there is
101 still "work" to do. In this example, the work is the asynchronous wait on the
102 timer, so the call will not return until the timer has expired and the
103 callback has completed.
105 It is important to remember to give the io_context some work to do before
106 calling boost::asio::io_context::run(). For example, if we had omitted the above call
107 to boost::asio::steady_timer::async_wait(), the io_context would not have had any
108 work to do, and consequently boost::asio::io_context::run() would have returned
114 See the \ref tuttimer2src "full source listing" \n
115 Return to the \ref index "tutorial index" \n
116 Previous: \ref tuttimer1 \n
122 \page tuttimer2src Source listing for Timer.2
123 \include timer2/timer.cpp
124 Return to \ref tuttimer2
128 \page tuttimer3 Timer.3 - Binding arguments to a handler
130 In this tutorial we will modify the program from tutorial Timer.2 so that the
131 timer fires once a second. This will show how to pass additional parameters to
132 your handler function.
134 \dontinclude timer3/timer.cpp
139 To implement a repeating timer using asio you need to change
140 the timer's expiry time in your callback function, and to then start a new
141 asynchronous wait. Obviously this means that the callback function will need
142 to be able to access the timer object. To this end we add two new parameters
143 to the <tt>print</tt> function:
145 \li A pointer to a timer object.
147 \li A counter so that we can stop the program when the timer fires for the
152 As mentioned above, this tutorial program uses a counter to
153 stop running when the timer fires for the sixth time. However you will observe
154 that there is no explicit call to ask the io_context to stop. Recall that in
155 tutorial Timer.2 we learnt that the boost::asio::io_context::run() function completes
156 when there is no more "work" to do. By not starting a new asynchronous wait on
157 the timer when <tt>count</tt> reaches 5, the io_context will run out of work and
162 Next we move the expiry time for the timer along by one second
163 from the previous expiry time. By calculating the new expiry time relative to
164 the old, we can ensure that the timer does not drift away from the
165 whole-second mark due to any delays in processing the handler.
169 Then we start a new asynchronous wait on the timer. As you can
170 see, the boost::bind() function is used to associate the extra parameters
171 with your callback handler. The boost::asio::steady_timer::async_wait() function
172 expects a handler function (or function object) with the signature
173 <tt>void(const boost::system::error_code&)</tt>. Binding the additional parameters
174 converts your <tt>print</tt> function into a function object that matches the
177 See the <a href="http://www.boost.org/libs/bind/bind.html">Boost.Bind
178 documentation</a> for more information on how to use boost::bind().
180 In this example, the boost::asio::placeholders::error argument to boost::bind() is a
181 named placeholder for the error object passed to the handler. When initiating
182 the asynchronous operation, and if using boost::bind(), you must specify only
183 the arguments that match the handler's parameter list. In tutorial Timer.4 you
184 will see that this placeholder may be elided if the parameter is not needed by
185 the callback handler.
187 \until boost::asio::io_context
189 A new <tt>count</tt> variable is added so that we can stop the
190 program when the timer fires for the sixth time.
192 \until boost::asio::steady_timer
194 As in Step 4, when making the call to
195 boost::asio::steady_timer::async_wait() from <tt>main</tt> we bind the additional
196 parameters needed for the <tt>print</tt> function.
200 Finally, just to prove that the <tt>count</tt> variable was
201 being used in the <tt>print</tt> handler function, we will print out its new
206 See the \ref tuttimer3src "full source listing" \n
207 Return to the \ref index "tutorial index" \n
208 Previous: \ref tuttimer2 \n
214 \page tuttimer3src Source listing for Timer.3
215 \include timer3/timer.cpp
216 Return to \ref tuttimer3
220 \page tuttimer4 Timer.4 - Using a member function as a handler
222 In this tutorial we will see how to use a class member function as a callback
223 handler. The program should execute identically to the tutorial program from
226 \dontinclude timer4/timer.cpp
231 Instead of defining a free function <tt>print</tt> as the
232 callback handler, as we did in the earlier tutorial programs, we now define a
233 class called <tt>printer</tt>.
237 The constructor of this class will take a reference to the
238 io_context object and use it when initialising the <tt>timer_</tt> member. The
239 counter used to shut down the program is now also a member of the class.
243 The boost::bind() function works just as well with class
244 member functions as with free functions. Since all non-static class member
245 functions have an implicit <tt>this</tt> parameter, we need to bind
246 <tt>this</tt> to the function. As in tutorial Timer.3, boost::bind()
247 converts our callback handler (now a member function) into a function object
248 that can be invoked as though it has the signature <tt>void(const
249 boost::system::error_code&)</tt>.
251 You will note that the boost::asio::placeholders::error placeholder is not specified
252 here, as the <tt>print</tt> member function does not accept an error object as
257 In the class destructor we will print out the final value of
262 The <tt>print</tt> member function is very similar to the
263 <tt>print</tt> function from tutorial Timer.3, except that it now operates on
264 the class data members instead of having the timer and counter passed in as
269 The <tt>main</tt> function is much simpler than before, as it
270 now declares a local <tt>printer</tt> object before running the io_context as
275 See the \ref tuttimer4src "full source listing" \n
276 Return to the \ref index "tutorial index" \n
277 Previous: \ref tuttimer3 \n
278 Next: \ref tuttimer5 \n
283 \page tuttimer4src Source listing for Timer.4
284 \include timer4/timer.cpp
285 Return to \ref tuttimer4
289 \page tuttimer5 Timer.5 - Synchronising handlers in multithreaded programs
291 This tutorial demonstrates the use of the boost::asio::strand class template to
292 synchronise callback handlers in a multithreaded program.
294 The previous four tutorials avoided the issue of handler synchronisation by
295 calling the boost::asio::io_context::run() function from one thread only. As you
296 already know, the asio library provides a guarantee that callback handlers will
297 <b>only</b> be called from threads that are currently calling
298 boost::asio::io_context::run(). Consequently, calling boost::asio::io_context::run() from
299 only one thread ensures that callback handlers cannot run concurrently.
301 The single threaded approach is usually the best place to start when
302 developing applications using asio. The downside is the limitations it places
303 on programs, particularly servers, including:
306 <li>Poor responsiveness when handlers can take a long time to complete.</li>
307 <li>An inability to scale on multiprocessor systems.</li>
310 If you find yourself running into these limitations, an alternative approach
311 is to have a pool of threads calling boost::asio::io_context::run(). However, as this
312 allows handlers to execute concurrently, we need a method of synchronisation
313 when handlers might be accessing a shared, thread-unsafe resource.
315 \dontinclude timer5/timer.cpp
320 We start by defining a class called <tt>printer</tt>, similar
321 to the class in the previous tutorial. This class will extend the previous
322 tutorial by running two timers in parallel.
326 In addition to initialising a pair of boost::asio::steady_timer members, the
327 constructor initialises the <tt>strand_</tt> member, an object of type
328 boost::asio::strand<boost::asio::io_context::executor_type>.
330 The boost::asio::strand class template is an executor adapter that guarantees
331 that, for those handlers that are dispatched through it, an executing handler
332 will be allowed to complete before the next one is started. This is guaranteed
333 irrespective of the number of threads that are calling
334 boost::asio::io_context::run(). Of course, the handlers may still execute
335 concurrently with other handlers that were <b>not</b> dispatched through an
336 boost::asio::strand, or were dispatched through a different boost::asio::strand
341 When initiating the asynchronous operations, each callback handler is "bound"
342 to an boost::asio::strand<boost::asio::io_context::executor_type> object. The
343 boost::asio::bind_executor() function returns a new handler that automatically
344 dispatches its contained handler through the boost::asio::strand object. By
345 binding the handlers to the same boost::asio::strand, we are ensuring that they
346 cannot execute concurrently.
351 In a multithreaded program, the handlers for asynchronous
352 operations should be synchronised if they access shared resources. In this
353 tutorial, the shared resources used by the handlers (<tt>print1</tt> and
354 <tt>print2</tt>) are <tt>std::cout</tt> and the <tt>count_</tt> data member.
358 The <tt>main</tt> function now causes boost::asio::io_context::run() to
359 be called from two threads: the main thread and one additional thread. This is
360 accomplished using an boost::thread object.
362 Just as it would with a call from a single thread, concurrent calls to
363 boost::asio::io_context::run() will continue to execute while there is "work" left to
364 do. The background thread will not exit until all asynchronous operations have
369 See the \ref tuttimer5src "full source listing" \n
370 Return to the \ref index "tutorial index" \n
371 Previous: \ref tuttimer4 \n
376 \page tuttimer5src Source listing for Timer.5
377 \include timer5/timer.cpp
378 Return to \ref tuttimer5