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).
8 [section:latches Latches -- EXPERIMENTAL]
10 [////////////////////]
11 [section Introdcution]
13 Latches are a thread co-ordination mechanism that allow one or more threads to block until one or more threads have reached a point.
16 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.
18 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.
25 Sample use cases for the latch include:
27 * Setting multiple threads to perform a task, and then waiting until all threads have reached a common point.
28 * Creating multiple threads, which wait for a signal before advancing beyond a common point.
30 An example of the first use case would be as follows:
32 void DoWork(thread_pool* pool) {
33 latch completion_latch(NTASKS);
34 for (int i = 0; i < NTASKS; ++i) {
38 completion_latch.count_down();
41 // Block until work is done
42 completion_latch.wait();
45 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.
49 vector<thread*> workers;
50 for (int i = 0; i < NTHREADS; ++i) {
51 workers.push_back(new thread([&] {
52 // Initialize data structures. This is CPU bound.
59 // Load input data. This is I/O bound.
61 // Threads can now start processing
62 start_latch.count_down();
66 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.
68 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.
72 size_t initial_threads;
73 atomic<size_t> current_threads(initial_threads)
74 vector<thread*> workers;
76 // Create a barrier, and set a lambda that will be invoked every time the
77 // barrier counts down. If one or more active threads have completed,
78 // reduce the number of threads.
79 completion_latch task_barrier(n_threads);
80 task_barrier.then([&] {
81 task_barrier.reset(current_threads);
84 for (int i = 0; i < n_threads; ++i) {
85 workers.push_back(new thread([&] {
88 Task task = tasks.get();
95 task_barrier.count_down_and_wait();
100 // Read each stage of the task until all stages are complete.
101 while (!finished()) {
108 [///////////////////////////]
109 [section:latch Class `latch`]
111 #include <boost/thread/latch.hpp>
116 latch(latch const&) = delete;
117 latch& operator=(latch const&) = delete;
119 latch(std::size_t count);
124 template <class Rep, class Period>
125 cv_status wait_for(const chrono::duration<Rep, Period>& rel_time);
126 template <class lock_type, class Clock, class Duration>
127 cv_status wait_until(const chrono::time_point<Clock, Duration>& abs_time);
129 void count_down_and_wait();
135 void reset(std::size_t count);
138 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.
140 Instances of __latch__ are not copyable or movable.
142 [///////////////////]
143 [section Constructor `latch(std::size_t)`]
145 latch(std::size_t count);
149 [[Effects:] [Construct a latch with is initial value for the internal counter.]]
151 [[Note:] [The counter could be zero.]]
153 [[Throws:] [Nothing.]]
159 [section Destructor `~latch()`]
165 [[Precondition:] [No threads are waiting or invoking count_down on `*this`.]]
167 [[Effects:] [Destroys `*this` latch.]]
169 [[Throws:] [Nothing.]]
174 [/////////////////////////////////////]
175 [section:wait Member Function `wait()`]
181 [[Effects:] [Block the calling thread until the internal count reaches the value zero. Then all waiting threads
185 - __thread_resource_error__ if an error occurs.
187 - __thread_interrupted__ if the wait was interrupted by a call to __interrupt__ on the __thread__ object associated with the current thread of execution.
190 [[Notes:] [`wait()` is an ['interruption point].]]
195 [/////////////////////////////////////////////]
196 [section:try_wait Member Function `try_wait()`]
202 [[Returns:] [Returns true if the internal count is 0, and false otherwise. Does not block the calling thread. ]]
205 - __thread_resource_error__ if an error occurs.
211 [//////////////////////////////////////////////]
212 [section:wait_for Member Function `wait_for() `]
214 template <class Rep, class Period>
215 cv_status wait_for(const chrono::duration<Rep, Period>& rel_time);
219 [[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. ]]
220 [[Returns:] [cv_status::no_timeout if the internal count is 0, and cv_status::timeout if duration has been elapsed. ]]
223 - __thread_resource_error__ if an error occurs.
225 - __thread_interrupted__ if the wait was interrupted by a call to __interrupt__ on the __thread__ object associated with the current thread of execution.
228 [[Notes:] [`wait_for()` is an ['interruption point].]]
233 [/////////////////////////////////////////////////]
234 [section:wait_until Member Function `wait_until()`]
236 template <class lock_type, class Clock, class Duration>
237 cv_status wait_until(const chrono::time_point<Clock, Duration>& abs_time);
241 [[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. ]]
242 [[Returns:] [cv_status::no_timeout if the internal count is 0, and cv_status::timeout if time_point has been reached.]]
245 - __thread_resource_error__ if an error occurs.
247 - __thread_interrupted__ if the wait was interrupted by a call to __interrupt__ on the __thread__ object associated with the current thread of execution.
250 [[Notes:] [`wait_until()` is an ['interruption point].]]
255 [/////////////////////////////////////////////////]
256 [section:count_down Member Function `count_down()`]
262 [[Requires:] [The internal counter is non zero.]]
263 [[Effects:] [Decrements the internal count by 1, and returns. If the count reaches 0, any threads blocked in wait() will be released. ]]
266 - __thread_resource_error__ if an error occurs.
268 - __thread_interrupted__ if the wait was interrupted by a call to __interrupt__ on the __thread__ object associated with the current thread of execution.
270 [[Notes:] [`count_down()` is an ['interruption point].]]
275 [///////////////////////////////////////////////////////////////////]
276 [section:count_down_and_wait Member Function `count_down_and_wait()`]
278 void count_down_and_wait();
282 [[Requires:] [The internal counter is non zero.]]
283 [[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(). ]]
286 - __thread_resource_error__ if an error occurs.
288 - __thread_interrupted__ if the wait was interrupted by a call to __interrupt__ on the __thread__ object associated with the current thread of execution.
290 [[Notes:] [`count_down_and_wait()` is an ['interruption point].]]
295 [///////////////////////////////////////]
297 [section:reset Member Function `reset()`]
303 [[Requires:] [This function may only be invoked when there are no other threads currently inside the waiting functions.]]
305 [[Returns:] [Resets the latch with a new value for the initial thread count. ]]
308 - __thread_resource_error__ if an error occurs.
318 [//////////////////////////////////////////////////]
319 [section:completion_latch Class `completion_latch `]
321 #include <boost/thread/completion_latch.hpp>
323 class completion_latch
326 typedef 'implementation defined' completion_function;
328 completion_latch(completion_latch const&) = delete;
329 completion_latch& operator=(completion_latch const&) = delete;
331 completion_latch(std::size_t count);
332 template <typename F>
333 completion_latch(std::size_t count, F&& funct);
338 template <class Rep, class Period>
339 cv_status wait_for(const chrono::duration<Rep, Period>& rel_time);
340 template <class lock_type, class Clock, class Duration>
341 cv_status wait_until(const chrono::time_point<Clock, Duration>& abs_time);
343 void count_down_and_wait();
344 void reset(std::size_t count);
345 template <typename F>
346 completion_function then(F&& funct);
350 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.
352 Instances of completion_latch are not copyable or movable.
354 Only the additional functions are documented.
356 [/////////////////////]
357 [section:c Constructor]
359 completion_latch(std::size_t count);
363 [[Effects:] [Construct a completion_latch with is initial value for the internal counter and a noop completion function.]]
365 [[Note:] [The counter could be zero and rest later.]]
367 [[Throws:] [Nothing.]]
372 [///////////////////////////////////////////////]
373 [section:cf Constructor with completion function]
375 template <typename F>
376 completion_latch(std::size_t count, F&& funct);
380 [[Effects:] [Construct a completion_latch with is initial value for the internal counter and the completion function `funct`.]]
382 [[Note:] [The counter could be zero and reset later.]]
386 - Any exception thrown by the copy/move construction of funct.
393 [///////////////////////////////////]
394 [section:then Member Function `then`]
396 template <typename F>
397 completion_function then(F&& funct);
401 [[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. ]]
403 [[Effects:] [Associates the parameter `funct` as completion function of the latch. The next time the internal count reaches 0, this function will be invoked.]]
404 [[Returns:] [The old completion function.]]
407 - __thread_resource_error__ if an error occurs.
409 - Any exception thrown by the copy/move construction of completion functions.
416 [endsect] [/ completion_latch]
419 [endsect] [/ Latches]