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