]> git.proxmox.com Git - ceph.git/blob - ceph/src/boost/libs/asio/example/cpp03/tutorial/timer_dox.txt
import quincy beta 17.1.0
[ceph.git] / ceph / src / boost / libs / asio / example / cpp03 / tutorial / timer_dox.txt
1 //
2 // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com)
3 //
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)
6 //
7
8 /**
9 \page tuttimer1 Timer.1 - Using a timer synchronously
10
11 This tutorial program introduces asio by showing how to perform a blocking
12 wait on a timer.
13
14 \dontinclude timer1/timer.cpp
15 \skip #include
16
17 We start by including the necessary header files.
18
19 All of the asio classes can be used by simply including the <tt>"asio.hpp"</tt>
20 header file.
21
22 \until asio.hpp
23
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.
28
29 \until boost::asio::io_context
30
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.
35
36 \until boost::asio::steady_timer
37
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
41 wait starts).
42
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
45 return immediately.
46
47 \until wait
48
49 Finally we print the obligatory <tt>"Hello, world!"</tt>
50 message to show when the timer has expired.
51
52 \until }
53
54 See the \ref tuttimer1src "full source listing" \n
55 Return to the \ref index "tutorial index" \n
56 Next: \ref tuttimer2
57
58 */
59
60 /**
61 \page tuttimer1src Source listing for Timer.1
62 \include timer1/timer.cpp
63 Return to \ref tuttimer1
64 */
65
66 /**
67 \page tuttimer2 Timer.2 - Using a timer asynchronously
68
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.
72
73 \dontinclude timer2/timer.cpp
74 \skip #include
75
76 \until asio.hpp
77
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.
82
83 \until boost::asio::steady_timer
84
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.
89
90 \skipline async_wait
91
92 Finally, we must call the boost::asio::io_context::run() member function
93 on the io_context object.
94
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.
99
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.
104
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
109 immediately.
110
111 \skip run
112 \until }
113
114 See the \ref tuttimer2src "full source listing" \n
115 Return to the \ref index "tutorial index" \n
116 Previous: \ref tuttimer1 \n
117 Next: \ref tuttimer3
118
119 */
120
121 /**
122 \page tuttimer2src Source listing for Timer.2
123 \include timer2/timer.cpp
124 Return to \ref tuttimer2
125 */
126
127 /**
128 \page tuttimer3 Timer.3 - Binding arguments to a handler
129
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.
133
134 \dontinclude timer3/timer.cpp
135 \skip #include
136
137 \until bind.hpp
138
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:
144
145 \li A pointer to a timer object.
146
147 \li A counter so that we can stop the program when the timer fires for the
148 sixth time.
149
150 \until {
151
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
158 stop running.
159
160 \until ++
161
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.
166
167 \until expires_at
168
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
175 signature correctly.
176
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().
179
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.
186
187 \until boost::asio::io_context
188
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.
191
192 \until boost::asio::steady_timer
193
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.
197
198 \until run
199
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
202 value.
203
204 \until }
205
206 See the \ref tuttimer3src "full source listing" \n
207 Return to the \ref index "tutorial index" \n
208 Previous: \ref tuttimer2 \n
209 Next: \ref tuttimer4
210
211 */
212
213 /**
214 \page tuttimer3src Source listing for Timer.3
215 \include timer3/timer.cpp
216 Return to \ref tuttimer3
217 */
218
219 /**
220 \page tuttimer4 Timer.4 - Using a member function as a handler
221
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
224 tutorial Timer.3.
225
226 \dontinclude timer4/timer.cpp
227 \skip #include
228
229 \until bind.hpp
230
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>.
234
235 \until public
236
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.
240
241 \until {
242
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>.
250
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
253 a parameter.
254
255 \until }
256
257 In the class destructor we will print out the final value of
258 the counter.
259
260 \until }
261
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
265 parameters.
266
267 \until };
268
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
271 normal.
272
273 \until }
274
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
279
280 */
281
282 /**
283 \page tuttimer4src Source listing for Timer.4
284 \include timer4/timer.cpp
285 Return to \ref tuttimer4
286 */
287
288 /**
289 \page tuttimer5 Timer.5 - Synchronising handlers in multithreaded programs
290
291 This tutorial demonstrates the use of the boost::asio::strand class template to
292 synchronise callback handlers in a multithreaded program.
293
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.
300
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:
304
305 <ul>
306 <li>Poor responsiveness when handlers can take a long time to complete.</li>
307 <li>An inability to scale on multiprocessor systems.</li>
308 </ul>
309
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.
314
315 \dontinclude timer5/timer.cpp
316 \skip #include
317
318 \until bind.hpp
319
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.
323
324 \until public
325
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>.
329
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
337 object.
338
339 \until {
340
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.
347
348 \until }
349 \until }
350
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.
355
356 \until };
357
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.
361
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
365 completed.
366
367 \until }
368
369 See the \ref tuttimer5src "full source listing" \n
370 Return to the \ref index "tutorial index" \n
371 Previous: \ref tuttimer4 \n
372
373 */
374
375 /**
376 \page tuttimer5src Source listing for Timer.5
377 \include timer5/timer.cpp
378 Return to \ref tuttimer5
379 */