latch.qbk 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419
  1. [/
  2. (C) Copyright 2013 Vicente J. Botet Escriba.
  3. Distributed under the Boost Software License, Version 1.0.
  4. (See accompanying file LICENSE_1_0.txt or copy at
  5. http://www.boost.org/LICENSE_1_0.txt).
  6. ]
  7. [section:latches Latches -- EXPERIMENTAL]
  8. [////////////////////]
  9. [section Introdcution]
  10. Latches are a thread co-ordination mechanism that allow one or more threads to block until one or more threads have reached a point.
  11. [/
  12. An individual latch is a reusable object; once the operation has been completed, the threads can re-use the same barrier. It is thus useful for managing repeated tasks handled by multiple threads.
  13. A completion latch is like a latch that allows to associate a completion function which will be called once the internal counter reaches the value 0 and all the consumer threads have taken care of the notification.
  14. ]
  15. [endsect]
  16. [////////////////]
  17. [section Examples]
  18. Sample use cases for the latch include:
  19. * Setting multiple threads to perform a task, and then waiting until all threads have reached a common point.
  20. * Creating multiple threads, which wait for a signal before advancing beyond a common point.
  21. An example of the first use case would be as follows:
  22. void DoWork(thread_pool* pool) {
  23. latch completion_latch(NTASKS);
  24. for (int i = 0; i < NTASKS; ++i) {
  25. pool->submit([&] {
  26. // perform work
  27. ...
  28. completion_latch.count_down();
  29. }));
  30. }
  31. // Block until work is done
  32. completion_latch.wait();
  33. }
  34. An example of the second use case is shown below. We need to load data and then process it using a number of threads. Loading the data is I/O bound, whereas starting threads and creating data structures is CPU bound. By running these in parallel, throughput can be increased.
  35. void DoWork() {
  36. latch start_latch(1);
  37. vector<thread*> workers;
  38. for (int i = 0; i < NTHREADS; ++i) {
  39. workers.push_back(new thread([&] {
  40. // Initialize data structures. This is CPU bound.
  41. ...
  42. start_latch.wait();
  43. // perform work
  44. ...
  45. }));
  46. }
  47. // Load input data. This is I/O bound.
  48. ...
  49. // Threads can now start processing
  50. start_latch.count_down();
  51. }
  52. [/
  53. The completion latches can be used to co-ordinate also a set of threads carrying out a repeated task. The number of threads can be adjusted dynamically to respond to changing requirements.
  54. In the example below, a number of threads are performing a multi-stage task. Some tasks may require fewer steps than others, meaning that some threads may finish before others. We reduce the number of threads waiting on the latch when this happens.
  55. void DoWork() {
  56. Tasks& tasks;
  57. size_t initial_threads;
  58. atomic<size_t> current_threads(initial_threads)
  59. vector<thread*> workers;
  60. // Create a barrier, and set a lambda that will be invoked every time the
  61. // barrier counts down. If one or more active threads have completed,
  62. // reduce the number of threads.
  63. completion_latch task_barrier(n_threads);
  64. task_barrier.then([&] {
  65. task_barrier.reset(current_threads);
  66. });
  67. for (int i = 0; i < n_threads; ++i) {
  68. workers.push_back(new thread([&] {
  69. bool active = true;
  70. while(active) {
  71. Task task = tasks.get();
  72. // perform task
  73. ...
  74. if (finished(task)) {
  75. current_threads--;
  76. active = false;
  77. }
  78. task_barrier.count_down_and_wait();
  79. }
  80. });
  81. }
  82. // Read each stage of the task until all stages are complete.
  83. while (!finished()) {
  84. GetNextStage(tasks);
  85. }
  86. }
  87. ]
  88. [endsect]
  89. [///////////////////////////]
  90. [section:latch Class `latch`]
  91. #include <boost/thread/latch.hpp>
  92. class latch
  93. {
  94. public:
  95. latch(latch const&) = delete;
  96. latch& operator=(latch const&) = delete;
  97. latch(std::size_t count);
  98. ~latch();
  99. void wait();
  100. bool try_wait();
  101. template <class Rep, class Period>
  102. cv_status wait_for(const chrono::duration<Rep, Period>& rel_time);
  103. template <class lock_type, class Clock, class Duration>
  104. cv_status wait_until(const chrono::time_point<Clock, Duration>& abs_time);
  105. void count_down();
  106. void count_down_and_wait();
  107. };
  108. [/
  109. void reset(std::size_t count);
  110. ]
  111. A latch maintains an internal counter that is initialized when the latch is created. One or more threads may block waiting until the counter is decremented to 0.
  112. Instances of __latch__ are not copyable or movable.
  113. [///////////////////]
  114. [section Constructor `latch(std::size_t)`]
  115. latch(std::size_t count);
  116. [variablelist
  117. [[Effects:] [Construct a latch with is initial value for the internal counter.]]
  118. [[Note:] [The counter could be zero.]]
  119. [[Throws:] [Nothing.]]
  120. ]
  121. [endsect]
  122. [//////////////////]
  123. [section Destructor `~latch()`]
  124. ~latch();
  125. [variablelist
  126. [[Precondition:] [No threads are waiting or invoking count_down on `*this`.]]
  127. [[Effects:] [Destroys `*this` latch.]]
  128. [[Throws:] [Nothing.]]
  129. ]
  130. [endsect]
  131. [/////////////////////////////////////]
  132. [section:wait Member Function `wait()`]
  133. void wait();
  134. [variablelist
  135. [[Effects:] [Block the calling thread until the internal count reaches the value zero. Then all waiting threads
  136. are unblocked. ]]
  137. [[Throws:] [
  138. - __thread_resource_error__ if an error occurs.
  139. - __thread_interrupted__ if the wait was interrupted by a call to __interrupt__ on the __thread__ object associated with the current thread of execution.
  140. ]]
  141. [[Notes:] [`wait()` is an ['interruption point].]]
  142. ]
  143. [endsect]
  144. [/////////////////////////////////////////////]
  145. [section:try_wait Member Function `try_wait()`]
  146. bool try_wait();
  147. [variablelist
  148. [[Returns:] [Returns true if the internal count is 0, and false otherwise. Does not block the calling thread. ]]
  149. [[Throws:] [
  150. - __thread_resource_error__ if an error occurs.
  151. ]]
  152. ]
  153. [endsect]
  154. [//////////////////////////////////////////////]
  155. [section:wait_for Member Function `wait_for() `]
  156. template <class Rep, class Period>
  157. cv_status wait_for(const chrono::duration<Rep, Period>& rel_time);
  158. [variablelist
  159. [[Effects:] [Block the calling thread until the internal count reaches the value zero or the duration has been elapsed. If no timeout, all waiting threads are unblocked. ]]
  160. [[Returns:] [cv_status::no_timeout if the internal count is 0, and cv_status::timeout if duration has been elapsed. ]]
  161. [[Throws:] [
  162. - __thread_resource_error__ if an error occurs.
  163. - __thread_interrupted__ if the wait was interrupted by a call to __interrupt__ on the __thread__ object associated with the current thread of execution.
  164. ]]
  165. [[Notes:] [`wait_for()` is an ['interruption point].]]
  166. ]
  167. [endsect]
  168. [/////////////////////////////////////////////////]
  169. [section:wait_until Member Function `wait_until()`]
  170. template <class lock_type, class Clock, class Duration>
  171. cv_status wait_until(const chrono::time_point<Clock, Duration>& abs_time);
  172. [variablelist
  173. [[Effects:] [Block the calling thread until the internal count reaches the value zero or the time_point has been reached. If no timeout, all waiting threads are unblocked. ]]
  174. [[Returns:] [cv_status::no_timeout if the internal count is 0, and cv_status::timeout if time_point has been reached.]]
  175. [[Throws:] [
  176. - __thread_resource_error__ if an error occurs.
  177. - __thread_interrupted__ if the wait was interrupted by a call to __interrupt__ on the __thread__ object associated with the current thread of execution.
  178. ]]
  179. [[Notes:] [`wait_until()` is an ['interruption point].]]
  180. ]
  181. [endsect]
  182. [/////////////////////////////////////////////////]
  183. [section:count_down Member Function `count_down()`]
  184. void count_down();
  185. [variablelist
  186. [[Requires:] [The internal counter is non zero.]]
  187. [[Effects:] [Decrements the internal count by 1, and returns. If the count reaches 0, any threads blocked in wait() will be released. ]]
  188. [[Throws:] [
  189. - __thread_resource_error__ if an error occurs.
  190. - __thread_interrupted__ if the wait was interrupted by a call to __interrupt__ on the __thread__ object associated with the current thread of execution.
  191. ]]
  192. [[Notes:] [`count_down()` is an ['interruption point].]]
  193. ]
  194. [endsect]
  195. [///////////////////////////////////////////////////////////////////]
  196. [section:count_down_and_wait Member Function `count_down_and_wait()`]
  197. void count_down_and_wait();
  198. [variablelist
  199. [[Requires:] [The internal counter is non zero.]]
  200. [[Effects:] [Decrements the internal count by 1. If the resulting count is not 0, blocks the calling thread until the internal count is decremented to 0 by one or more other threads calling count_down() or count_down_and_wait(). ]]
  201. [[Throws:] [
  202. - __thread_resource_error__ if an error occurs.
  203. - __thread_interrupted__ if the wait was interrupted by a call to __interrupt__ on the __thread__ object associated with the current thread of execution.
  204. ]]
  205. [[Notes:] [`count_down_and_wait()` is an ['interruption point].]]
  206. ]
  207. [endsect]
  208. [///////////////////////////////////////]
  209. [
  210. [section:reset Member Function `reset()`]
  211. reset( size_t );
  212. [variablelist
  213. [[Requires:] [This function may only be invoked when there are no other threads currently inside the waiting functions.]]
  214. [[Returns:] [Resets the latch with a new value for the initial thread count. ]]
  215. [[Throws:] [
  216. - __thread_resource_error__ if an error occurs.
  217. ]]
  218. ]
  219. [endsect]
  220. ]
  221. [endsect] [/ latch]
  222. [/
  223. [//////////////////////////////////////////////////]
  224. [section:completion_latch Class `completion_latch `]
  225. #include <boost/thread/completion_latch.hpp>
  226. class completion_latch
  227. {
  228. public:
  229. typedef 'implementation defined' completion_function;
  230. completion_latch(completion_latch const&) = delete;
  231. completion_latch& operator=(completion_latch const&) = delete;
  232. completion_latch(std::size_t count);
  233. template <typename F>
  234. completion_latch(std::size_t count, F&& funct);
  235. ~completion_latch();
  236. void wait();
  237. bool try_wait();
  238. template <class Rep, class Period>
  239. cv_status wait_for(const chrono::duration<Rep, Period>& rel_time);
  240. template <class lock_type, class Clock, class Duration>
  241. cv_status wait_until(const chrono::time_point<Clock, Duration>& abs_time);
  242. void count_down();
  243. void count_down_and_wait();
  244. void reset(std::size_t count);
  245. template <typename F>
  246. completion_function then(F&& funct);
  247. };
  248. A completion latch is like a latch that allows to associate a completion function which will be called once the internal counter reaches the value 0 and all the consumer threads have taken care of the notification.
  249. Instances of completion_latch are not copyable or movable.
  250. Only the additional functions are documented.
  251. [/////////////////////]
  252. [section:c Constructor]
  253. completion_latch(std::size_t count);
  254. [variablelist
  255. [[Effects:] [Construct a completion_latch with is initial value for the internal counter and a noop completion function.]]
  256. [[Note:] [The counter could be zero and rest later.]]
  257. [[Throws:] [Nothing.]]
  258. ]
  259. [endsect]
  260. [///////////////////////////////////////////////]
  261. [section:cf Constructor with completion function]
  262. template <typename F>
  263. completion_latch(std::size_t count, F&& funct);
  264. [variablelist
  265. [[Effects:] [Construct a completion_latch with is initial value for the internal counter and the completion function `funct`.]]
  266. [[Note:] [The counter could be zero and reset later.]]
  267. [[Throws:] [
  268. - Any exception thrown by the copy/move construction of funct.
  269. ]]
  270. ]
  271. [endsect]
  272. [///////////////////////////////////]
  273. [section:then Member Function `then`]
  274. template <typename F>
  275. completion_function then(F&& funct);
  276. [variablelist
  277. [[Requires:] [This function may only be invoked when there are no other threads currently inside the waiting functions. It may also be invoked from within the registered completion function. ]]
  278. [[Effects:] [Associates the parameter `funct` as completion function of the latch. The next time the internal count reaches 0, this function will be invoked.]]
  279. [[Returns:] [The old completion function.]]
  280. [[Throws:] [
  281. - __thread_resource_error__ if an error occurs.
  282. - Any exception thrown by the copy/move construction of completion functions.
  283. ]]
  284. ]
  285. [endsect]
  286. [endsect] [/ completion_latch]
  287. ]
  288. [endsect] [/ Latches]