]> git.proxmox.com Git - ceph.git/blob - ceph/src/boost/libs/asio/example/cpp03/tutorial/timer_dox.txt
update source to Ceph Pacific 16.2.2
[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 boost::asio::io_context object.
25 This class provides access to I/O functionality. We declare an object of this
26 type first thing in the main function.
27
28 \until boost::asio::io_context
29
30 Next we declare an object of type boost::asio::steady_timer. The core asio classes
31 that provide I/O functionality (or as in this case timer functionality) always
32 take a reference to an io_context as their first constructor argument. The
33 second argument to the constructor sets the timer to expire 5 seconds from now.
34
35 \until boost::asio::steady_timer
36
37 In this simple example we perform a blocking wait on the timer.
38 That is, the call to boost::asio::steady_timer::wait() will not return until the
39 timer has expired, 5 seconds after it was created (i.e. <b>not</b> from when the
40 wait starts).
41
42 A timer is always in one of two states: "expired" or "not expired". If the
43 boost::asio::steady_timer::wait() function is called on an expired timer, it will
44 return immediately.
45
46 \until wait
47
48 Finally we print the obligatory <tt>"Hello, world!"</tt>
49 message to show when the timer has expired.
50
51 \until }
52
53 See the \ref tuttimer1src "full source listing" \n
54 Return to the \ref index "tutorial index" \n
55 Next: \ref tuttimer2
56
57 */
58
59 /**
60 \page tuttimer1src Source listing for Timer.1
61 \include timer1/timer.cpp
62 Return to \ref tuttimer1
63 */
64
65 /**
66 \page tuttimer2 Timer.2 - Using a timer asynchronously
67
68 This tutorial program demonstrates how to use asio's asynchronous callback
69 functionality by modifying the program from tutorial Timer.1 to perform an
70 asynchronous wait on the timer.
71
72 \dontinclude timer2/timer.cpp
73 \skip #include
74
75 \until asio.hpp
76
77 Using asio's asynchronous functionality means having a callback
78 function that will be called when an asynchronous operation completes. In this
79 program we define a function called <tt>print</tt> to be called when the
80 asynchronous wait finishes.
81
82 \until boost::asio::steady_timer
83
84 Next, instead of doing a blocking wait as in tutorial Timer.1,
85 we call the boost::asio::steady_timer::async_wait() function to perform an
86 asynchronous wait. When calling this function we pass the <tt>print</tt>
87 callback handler that was defined above.
88
89 \skipline async_wait
90
91 Finally, we must call the boost::asio::io_context::run() member function
92 on the io_context object.
93
94 The asio library provides a guarantee that callback handlers will <b>only</b>
95 be called from threads that are currently calling boost::asio::io_context::run().
96 Therefore unless the boost::asio::io_context::run() function is called the callback for
97 the asynchronous wait completion will never be invoked.
98
99 The boost::asio::io_context::run() function will also continue to run while there is
100 still "work" to do. In this example, the work is the asynchronous wait on the
101 timer, so the call will not return until the timer has expired and the
102 callback has completed.
103
104 It is important to remember to give the io_context some work to do before
105 calling boost::asio::io_context::run(). For example, if we had omitted the above call
106 to boost::asio::steady_timer::async_wait(), the io_context would not have had any
107 work to do, and consequently boost::asio::io_context::run() would have returned
108 immediately.
109
110 \skip run
111 \until }
112
113 See the \ref tuttimer2src "full source listing" \n
114 Return to the \ref index "tutorial index" \n
115 Previous: \ref tuttimer1 \n
116 Next: \ref tuttimer3
117
118 */
119
120 /**
121 \page tuttimer2src Source listing for Timer.2
122 \include timer2/timer.cpp
123 Return to \ref tuttimer2
124 */
125
126 /**
127 \page tuttimer3 Timer.3 - Binding arguments to a handler
128
129 In this tutorial we will modify the program from tutorial Timer.2 so that the
130 timer fires once a second. This will show how to pass additional parameters to
131 your handler function.
132
133 \dontinclude timer3/timer.cpp
134 \skip #include
135
136 \until bind.hpp
137
138 To implement a repeating timer using asio you need to change
139 the timer's expiry time in your callback function, and to then start a new
140 asynchronous wait. Obviously this means that the callback function will need
141 to be able to access the timer object. To this end we add two new parameters
142 to the <tt>print</tt> function:
143
144 \li A pointer to a timer object.
145
146 \li A counter so that we can stop the program when the timer fires for the
147 sixth time.
148
149 \until {
150
151 As mentioned above, this tutorial program uses a counter to
152 stop running when the timer fires for the sixth time. However you will observe
153 that there is no explicit call to ask the io_context to stop. Recall that in
154 tutorial Timer.2 we learnt that the boost::asio::io_context::run() function completes
155 when there is no more "work" to do. By not starting a new asynchronous wait on
156 the timer when <tt>count</tt> reaches 5, the io_context will run out of work and
157 stop running.
158
159 \until ++
160
161 Next we move the expiry time for the timer along by one second
162 from the previous expiry time. By calculating the new expiry time relative to
163 the old, we can ensure that the timer does not drift away from the
164 whole-second mark due to any delays in processing the handler.
165
166 \until expires_at
167
168 Then we start a new asynchronous wait on the timer. As you can
169 see, the boost::bind() function is used to associate the extra parameters
170 with your callback handler. The boost::asio::steady_timer::async_wait() function
171 expects a handler function (or function object) with the signature
172 <tt>void(const boost::system::error_code&)</tt>. Binding the additional parameters
173 converts your <tt>print</tt> function into a function object that matches the
174 signature correctly.
175
176 See the <a href="http://www.boost.org/libs/bind/bind.html">Boost.Bind
177 documentation</a> for more information on how to use boost::bind().
178
179 In this example, the boost::asio::placeholders::error argument to boost::bind() is a
180 named placeholder for the error object passed to the handler. When initiating
181 the asynchronous operation, and if using boost::bind(), you must specify only
182 the arguments that match the handler's parameter list. In tutorial Timer.4 you
183 will see that this placeholder may be elided if the parameter is not needed by
184 the callback handler.
185
186 \until boost::asio::io_context
187
188 A new <tt>count</tt> variable is added so that we can stop the
189 program when the timer fires for the sixth time.
190
191 \until boost::asio::steady_timer
192
193 As in Step 4, when making the call to
194 boost::asio::steady_timer::async_wait() from <tt>main</tt> we bind the additional
195 parameters needed for the <tt>print</tt> function.
196
197 \until run
198
199 Finally, just to prove that the <tt>count</tt> variable was
200 being used in the <tt>print</tt> handler function, we will print out its new
201 value.
202
203 \until }
204
205 See the \ref tuttimer3src "full source listing" \n
206 Return to the \ref index "tutorial index" \n
207 Previous: \ref tuttimer2 \n
208 Next: \ref tuttimer4
209
210 */
211
212 /**
213 \page tuttimer3src Source listing for Timer.3
214 \include timer3/timer.cpp
215 Return to \ref tuttimer3
216 */
217
218 /**
219 \page tuttimer4 Timer.4 - Using a member function as a handler
220
221 In this tutorial we will see how to use a class member function as a callback
222 handler. The program should execute identically to the tutorial program from
223 tutorial Timer.3.
224
225 \dontinclude timer4/timer.cpp
226 \skip #include
227
228 \until bind.hpp
229
230 Instead of defining a free function <tt>print</tt> as the
231 callback handler, as we did in the earlier tutorial programs, we now define a
232 class called <tt>printer</tt>.
233
234 \until public
235
236 The constructor of this class will take a reference to the
237 io_context object and use it when initialising the <tt>timer_</tt> member. The
238 counter used to shut down the program is now also a member of the class.
239
240 \until {
241
242 The boost::bind() function works just as well with class
243 member functions as with free functions. Since all non-static class member
244 functions have an implicit <tt>this</tt> parameter, we need to bind
245 <tt>this</tt> to the function. As in tutorial Timer.3, boost::bind()
246 converts our callback handler (now a member function) into a function object
247 that can be invoked as though it has the signature <tt>void(const
248 boost::system::error_code&)</tt>.
249
250 You will note that the boost::asio::placeholders::error placeholder is not specified
251 here, as the <tt>print</tt> member function does not accept an error object as
252 a parameter.
253
254 \until }
255
256 In the class destructor we will print out the final value of
257 the counter.
258
259 \until }
260
261 The <tt>print</tt> member function is very similar to the
262 <tt>print</tt> function from tutorial Timer.3, except that it now operates on
263 the class data members instead of having the timer and counter passed in as
264 parameters.
265
266 \until };
267
268 The <tt>main</tt> function is much simpler than before, as it
269 now declares a local <tt>printer</tt> object before running the io_context as
270 normal.
271
272 \until }
273
274 See the \ref tuttimer4src "full source listing" \n
275 Return to the \ref index "tutorial index" \n
276 Previous: \ref tuttimer3 \n
277 Next: \ref tuttimer5 \n
278
279 */
280
281 /**
282 \page tuttimer4src Source listing for Timer.4
283 \include timer4/timer.cpp
284 Return to \ref tuttimer4
285 */
286
287 /**
288 \page tuttimer5 Timer.5 - Synchronising handlers in multithreaded programs
289
290 This tutorial demonstrates the use of the boost::asio::strand class template to
291 synchronise callback handlers in a multithreaded program.
292
293 The previous four tutorials avoided the issue of handler synchronisation by
294 calling the boost::asio::io_context::run() function from one thread only. As you
295 already know, the asio library provides a guarantee that callback handlers will
296 <b>only</b> be called from threads that are currently calling
297 boost::asio::io_context::run(). Consequently, calling boost::asio::io_context::run() from
298 only one thread ensures that callback handlers cannot run concurrently.
299
300 The single threaded approach is usually the best place to start when
301 developing applications using asio. The downside is the limitations it places
302 on programs, particularly servers, including:
303
304 <ul>
305 <li>Poor responsiveness when handlers can take a long time to complete.</li>
306 <li>An inability to scale on multiprocessor systems.</li>
307 </ul>
308
309 If you find yourself running into these limitations, an alternative approach
310 is to have a pool of threads calling boost::asio::io_context::run(). However, as this
311 allows handlers to execute concurrently, we need a method of synchronisation
312 when handlers might be accessing a shared, thread-unsafe resource.
313
314 \dontinclude timer5/timer.cpp
315 \skip #include
316
317 \until bind.hpp
318
319 We start by defining a class called <tt>printer</tt>, similar
320 to the class in the previous tutorial. This class will extend the previous
321 tutorial by running two timers in parallel.
322
323 \until public
324
325 In addition to initialising a pair of boost::asio::steady_timer members, the
326 constructor initialises the <tt>strand_</tt> member, an object of type
327 boost::asio::strand<boost::asio::io_context::executor_type>.
328
329 The boost::asio::strand class template is an executor adapter that guarantees
330 that, for those handlers that are dispatched through it, an executing handler
331 will be allowed to complete before the next one is started. This is guaranteed
332 irrespective of the number of threads that are calling
333 boost::asio::io_context::run(). Of course, the handlers may still execute
334 concurrently with other handlers that were <b>not</b> dispatched through an
335 boost::asio::strand, or were dispatched through a different boost::asio::strand
336 object.
337
338 \until {
339
340 When initiating the asynchronous operations, each callback handler is "bound"
341 to an boost::asio::strand<boost::asio::io_context::executor_type> object. The
342 boost::asio::bind_executor() function returns a new handler that automatically
343 dispatches its contained handler through the boost::asio::strand object. By
344 binding the handlers to the same boost::asio::strand, we are ensuring that they
345 cannot execute concurrently.
346
347 \until }
348 \until }
349
350 In a multithreaded program, the handlers for asynchronous
351 operations should be synchronised if they access shared resources. In this
352 tutorial, the shared resources used by the handlers (<tt>print1</tt> and
353 <tt>print2</tt>) are <tt>std::cout</tt> and the <tt>count_</tt> data member.
354
355 \until };
356
357 The <tt>main</tt> function now causes boost::asio::io_context::run() to
358 be called from two threads: the main thread and one additional thread. This is
359 accomplished using an boost::thread object.
360
361 Just as it would with a call from a single thread, concurrent calls to
362 boost::asio::io_context::run() will continue to execute while there is "work" left to
363 do. The background thread will not exit until all asynchronous operations have
364 completed.
365
366 \until }
367
368 See the \ref tuttimer5src "full source listing" \n
369 Return to the \ref index "tutorial index" \n
370 Previous: \ref tuttimer4 \n
371
372 */
373
374 /**
375 \page tuttimer5src Source listing for Timer.5
376 \include timer5/timer.cpp
377 Return to \ref tuttimer5
378 */