timer_dox.txt 13 KB

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