]> git.proxmox.com Git - ceph.git/blame - ceph/src/boost/libs/fiber/doc/condition_variables.qbk
bump version to 12.2.2-pve1
[ceph.git] / ceph / src / boost / libs / fiber / doc / condition_variables.qbk
CommitLineData
7c673cae
FG
1[/
2 (C) Copyright 2007-8 Anthony Williams.
3 (C) Copyright 2013 Oliver Kowalke.
4 Distributed under the Boost Software License, Version 1.0.
5 (See accompanying file LICENSE_1_0.txt or copy at
6 http://www.boost.org/LICENSE_1_0.txt).
7]
8
9[section:conditions Condition Variables]
10
11[heading Synopsis]
12
13 enum class cv_status; {
14 no_timeout,
15 timeout
16 };
17
18 class condition_variable;
19 class condition_variable_any;
20
21The class [class_link condition_variable] provides a mechanism for a fiber to
22wait for notification from another fiber. When the fiber awakens from the
23wait, then it checks to see if the appropriate condition is now true, and
24continues if so. If the condition is not true, then the fiber calls `wait`
25again to resume waiting. In the simplest case, this condition is just a
26boolean variable:
27
28 boost::fibers::condition_variable cond;
29 boost::fibers::mutex mtx;
30 bool data_ready = false;
31
32 void process_data();
33
34 void wait_for_data_to_process() {
35 {
36 std::unique_lock< boost::fibers::mutex > lk( mtx);
37 while ( ! data_ready) {
38 cond.wait( lk);
39 }
40 } // release lk
41 process_data();
42 }
43
44Notice that the `lk` is passed to [member_link condition_variable..wait]:
45`wait()` will atomically add the fiber to the set of fibers waiting on the
46condition variable, and unlock the [class_link mutex]. When the fiber is
47awakened, the `mutex` will be locked again before the call to `wait()`
48returns. This allows other fibers to acquire the `mutex` in order to update
49the shared data, and ensures that the data associated with the condition is
50correctly synchronized.
51
52`wait_for_data_to_process()` could equivalently be written:
53
54 void wait_for_data_to_process() {
55 {
56 std::unique_lock< boost::fibers::mutex > lk( mtx);
57 // make condition_variable::wait() perform the loop
58 cond.wait( lk, [](){ return data_ready; });
59 } // release lk
60 process_data();
61 }
62
63In the meantime, another fiber sets `data_ready` to `true`, and then calls
64either [member_link condition_variable..notify_one] or [member_link
65condition_variable..notify_all] on the [class_link condition_variable] `cond`
66to wake one waiting fiber or all the waiting fibers respectively.
67
68 void retrieve_data();
69 void prepare_data();
70
71 void prepare_data_for_processing() {
72 retrieve_data();
73 prepare_data();
74 {
75 std::unique_lock< boost::fibers::mutex > lk( mtx);
76 data_ready = true;
77 }
78 cond.notify_one();
79 }
80
81Note that the same [class_link mutex] is locked before the shared data is
82updated, but that the `mutex` does not have to be locked across the call to
83[member_link condition_variable..notify_one].
84
85Locking is important because the synchronization objects provided by
86__boost_fiber__ can be used to synchronize fibers running on different
87threads.
88
89__boost_fiber__ provides both [class_link condition_variable] and [class_link
90condition_variable_any]. `boost::fibers::condition_variable` can only wait on
91__unique_lock__`< boost::fibers::`[class_link mutex]` >` while
92`boost::fibers::condition_variable_any` can wait on user-defined lock types.
93
94[#condition_variable_spurious_wakeups]
95[heading No Spurious Wakeups]
96
97Neither [class_link condition_variable] nor [class_link
98condition_variable_any] are subject to spurious wakeup:
99[member_link condition_variable..wait] can only wake up when
100[member_link condition_variable..notify_one] or
101[member_link condition_variable..notify_all] is called. Even so, it is prudent
102to use one of the `wait( lock, predicate )` overloads.
103
104Consider a set of consumer fibers processing items from a
105[@http://en.cppreference.com/w/cpp/container/queue `std::queue`]. The queue is
106continually populated by a set of producer fibers.
107
108The consumer fibers might reasonably wait on a `condition_variable` as long as
109the queue remains [@http://en.cppreference.com/w/cpp/container/queue/empty
110`empty()`].
111
112Because producer fibers might
113[@http://en.cppreference.com/w/cpp/container/queue/push `push()`] items to the
114queue in bursts, they call [member_link condition_variable..notify_all] rather
115than [member_link condition_variable..notify_one].
116
117But a given consumer fiber might well wake up from [member_link
118condition_variable..wait] and find the queue `empty()`, because other consumer
119fibers might already have processed all pending items.
120
121(See also [link spurious_wakeup spurious wakeup].)
122
123[#class_cv_status]
124[heading Enumeration `cv_status`]
125
126A timed wait operation might return because of timeout or not.
127
128 enum class cv_status {
129 no_timeout,
130 timeout
131 };
132
133[heading `no_timeout`]
134[variablelist
135[[Effects:] [The condition variable was awakened with `notify_one` or `notify_all`.]]
136]
137
138[heading `timeout`]
139[variablelist
140[[Effects:] [The condition variable was awakened by timeout.]]
141]
142
143[/ The documentation for condition_variable_any and condition_variable is so
144 nearly identical that we define a QuickBook template to capture its
145 essentials. Differences are:
146 the classname (of course),
147 the locktype (a LockType template param vs. std::unique_lock<mutex>),
148 the template parameter 'typename LockType',
149 and -- for when it's the only template parameter -- the return type plus
150 the template prefix 'template <typename LockType> void'.
151 The last two really want to just vanish for condition_variable, but since
152 you can't pass empty parameters to a QuickBook template (why??), the
153 template_rtype param must supply the return type as well as the template <>
154 clause, and the template_arg parameter must supply the 'typename' for the
155 next template parameter as well as 'typename LockType'.]
156[template condition_variable_x[classname locktype template_rtype template_arg]
157[class_heading [classname]]
158
159 #include <boost/fiber/condition_variable.hpp>
160
161 namespace boost {
162 namespace fibers {
163
164 class ``[classname]`` {
165 public:
166 ``[classname]``();
167 ~``[classname]``();
168
169 ``[classname]``( ``[classname]`` const&) = delete;
170 ``[classname]`` & operator=( ``[classname]`` const&) = delete;
171
172 void notify_one() noexcept;
173 void notify_all() noexcept;
174
175 ``[template_rtype]`` wait( ``[locktype]`` &);
176
177 template< ``[template_arg]`` Pred >
178 void wait( ``[locktype]`` &, Pred);
179
180 template< ``[template_arg]`` Clock, typename Duration >
181 cv_status wait_until( ``[locktype]`` &,
182 std::chrono::time_point< Clock, Duration > const&);
183
184 template< ``[template_arg]`` Clock, typename Duration, typename Pred >
185 bool wait_until( ``[locktype]`` &,
186 std::chrono::time_point< Clock, Duration > const&,
187 Pred);
188
189 template< ``[template_arg]`` Rep, typename Period >
190 cv_status wait_for( ``[locktype]`` &,
191 std::chrono::duration< Rep, Period > const&);
192
193 template< ``[template_arg]`` Rep, typename Period, typename Pred >
194 bool wait_for( ``[locktype]`` &,
195 std::chrono::duration< Rep, Period > const&,
196 Pred);
197 };
198
199 }}
200
201[heading Constructor]
202
203 ``[classname]``()
204
205[variablelist
206[[Effects:] [Creates the object.]]
207[[Throws:] [Nothing.]]
208]
209
210[heading Destructor]
211
212 ~``[classname]``()
213
214[variablelist
215[[Precondition:] [All fibers waiting on `*this` have been notified by a call to
216`notify_one` or `notify_all` (though the respective calls to `wait`, `wait_for` or
217`wait_until` need not have returned).]]
218[[Effects:] [Destroys the object.]]
219]
220
221[member_heading [classname]..notify_one]
222
223 void notify_one() noexcept;
224
225[variablelist
226[[Effects:] [If any fibers are currently __blocked__ waiting on `*this` in a
227call to `wait`, `wait_for` or `wait_until`, unblocks one of those fibers.]]
228[[Throws:] [Nothing.]]
229[[Note:] [It is arbitrary which waiting fiber is resumed.]]
230]
231
232[member_heading [classname]..notify_all]
233
234 void notify_all() noexcept;
235
236[variablelist
237[[Effects:] [If any fibers are currently __blocked__ waiting on `*this` in a
238call to `wait`, `wait_for` or `wait_until`, unblocks all of those fibers.]]
239[[Throws:] [Nothing.]]
240[[Note:] [This is why a waiting fiber must ['also] check for the desired
241program state using a mechanism external to the [`[classname]], and
242retry the wait until that state is reached. A fiber waiting on a
243[`[classname]] might well wake up a number of times before the desired
244state is reached.]]
245]
246
247[template_member_heading [classname]..wait]
248
249 ``[template_rtype]`` wait( ``[locktype]`` & lk);
250
251 template< ``[template_arg]`` Pred >
252 void wait( ``[locktype]`` & lk, Pred pred);
253
254[variablelist
255[[Precondition:] [`lk` is locked by the current fiber, and either no other
256fiber is currently waiting on `*this`, or the execution of the
257[@http://en.cppreference.com/w/cpp/thread/unique_lock/mutex `mutex()`]
258member function on the `lk` objects supplied in the calls to `wait` in all the
259fibers currently waiting on `*this` would return the same value as
260`lk->mutex()` for this call to `wait`.]]
261[[Effects:] [Atomically call `lk.unlock()` and blocks the current fiber. The
262fiber will unblock when notified by a call to `this->notify_one()` or
263`this->notify_all()`. When the fiber is unblocked (for whatever
264reason), the lock is reacquired by invoking `lk.lock()` before the call to
265`wait` returns. The lock is also reacquired by invoking `lk.lock()` if the
266function exits with an exception.
267The member function accepting `pred` is shorthand for: ``
268
269while ( ! pred() ) {
270 wait( lk);
271}
272``]]
273[[Postcondition:] [`lk` is locked by the current fiber.]]
274[[Throws:] [__fiber_error__ if an error occurs.]]
275[[Note:] [The Precondition is a bit dense. It merely states that all the
276fibers concurrently calling `wait` on `*this` must wait on `lk` objects
277governing the ['same] [class_link mutex]. Three distinct objects are involved
278in any [`[classname]::wait()] call: the [`[classname]] itself, the `mutex`
279coordinating access between fibers and a local lock object (e.g.
280__unique_lock__). In general, you can partition the lifespan of a given
281[`[classname]] instance into periods with one or more fibers waiting on it,
282separated by periods when no fibers are waiting on it. When more than one
283fiber is waiting on that [`[classname]], all must pass lock objects
284referencing the ['same] `mutex` instance.]]
285]
286
287[template_member_heading [classname]..wait_until]
288
289 template< ``[template_arg]`` Clock, typename Duration >
290 cv_status wait_until( ``[locktype]`` & lk,
291 std::chrono::time_point< Clock, Duration > const& abs_time);
292
293 template< ``[template_arg]`` Clock, typename Duration, typename Pred >
294 bool wait_until( ``[locktype]`` & lk,
295 std::chrono::time_point< Clock, Duration > const& abs_time,
296 Pred pred);
297
298[variablelist
299[[Precondition:] [`lk` is locked by the current fiber, and either no other
300fiber is currently waiting on `*this`, or the execution of the `mutex()` member
301function on the `lk` objects supplied in the calls to `wait`, `wait_for` or
302`wait_until` in all the fibers currently waiting on `*this` would return the
303same value as `lk.mutex()` for this call to `wait_until`.]]
304[[Effects:] [Atomically call `lk.unlock()` and blocks the current fiber. The
305fiber will unblock when notified by a call to `this->notify_one()` or
306`this->notify_all()`, when the system time
307would be equal to or later than the specified `abs_time`.
308When the fiber is unblocked (for whatever reason), the lock is reacquired by
309invoking `lk.lock()` before the call to `wait_until` returns. The lock is also
310reacquired by invoking `lk.lock()` if the function exits with an exception.
311The member function accepting `pred` is shorthand for: ``
312
313while ( ! pred() ) {
314 if ( cv_status::timeout == wait_until( lk, abs_time) )
315 return pred();
316}
317return true;
318
319`` That is, even if `wait_until()` times out, it can still return `true` if
320`pred()` returns `true` at that time.]]
321[[Postcondition:] [`lk` is locked by the current fiber.]]
322[[Throws:] [__fiber_error__ if an error
323occurs or timeout-related exceptions.]]
324[[Returns:] [The overload without `pred` returns `cv_status::no_timeout` if
325awakened by `notify_one()` or `notify_all()`, or `cv_status::timeout` if
326awakened because the system time is past `abs_time`.]]
327[[Returns:] [The overload accepting `pred` returns `false` if the call is
328returning because the time specified by `abs_time` was reached and the
329predicate returns `false`, `true` otherwise.]]
330[[Note:] [See [*Note] for [member_link [classname]..wait].]]
331]
332
333[template_member_heading [classname]..wait_for]
334
335 template< ``[template_arg]`` Rep, typename Period >
336 cv_status wait_for( ``[locktype]`` & lk,
337 std::chrono::duration< Rep, Period > const& rel_time);
338
339 template< ``[template_arg]`` Rep, typename Period, typename Pred >
340 bool wait_for( ``[locktype]`` & lk,
341 std::chrono::duration< Rep, Period > const& rel_time,
342 Pred pred);
343
344[variablelist
345[[Precondition:] [`lk` is locked by the current fiber, and either no other
346fiber is currently waiting on `*this`, or the execution of the `mutex()` member
347function on the `lk` objects supplied in the calls to `wait`, `wait_for` or
348`wait_until` in all the fibers currently waiting on `*this` would return the
349same value as `lk.mutex()` for this call to `wait_for`.]]
350[[Effects:] [Atomically call `lk.unlock()` and blocks the current fiber. The
351fiber will unblock when notified by a call to `this->notify_one()` or
352`this->notify_all()`, when a time interval equal to or greater than the
353specified `rel_time` has elapsed. When the fiber is
354unblocked (for whatever reason), the lock is reacquired by invoking
355`lk.lock()` before the call to `wait` returns. The lock is also reacquired by
356invoking `lk.lock()` if the function exits with an exception.
357The `wait_for()` member function accepting `pred` is shorthand for: ``
358
359while ( ! pred() ) {
360 if ( cv_status::timeout == wait_for( lk, rel_time) ) {
361 return pred();
362 }
363}
364return true;
365
366`` (except of course that `rel_time` is adjusted for each iteration).
367The point is that, even if `wait_for()` times out, it can still return `true`
368if `pred()` returns `true` at that time.]]
369[[Postcondition:] [`lk` is locked by the current fiber.]]
370[[Throws:] [__fiber_error__ if an error
371occurs or timeout-related exceptions.]]
372[[Returns:] [The overload without `pred` returns `cv_status::no_timeout` if
373awakened by `notify_one()` or `notify_all()`, or `cv_status::timeout` if
374awakened because at least `rel_time` has elapsed.]]
375[[Returns:] [The overload accepting `pred` returns `false` if the call is
376returning because at least `rel_time` has elapsed and the predicate
377returns `false`, `true` otherwise.]]
378[[Note:] [See [*Note] for [member_link [classname]..wait].]]
379]
380]
381[/ The above is the template describing both condition_variable_any and
382 condition_variable. We must invoke it to generate those descriptions. First
383 condition_variable_any, which accepts any LockType. Because a QuickBook
384 template argument cannot be empty, the template<> prefix must also supply
385 the 'void' return type for wait(); likewise the 'typename LockType'
386 template argument must also supply the following 'typename'.]
387[condition_variable_x condition_variable_any..LockType..template< typename LockType >
388 void..typename LockType, typename]
389[/ Now condition_variable, which accepts specifically std::unique_lock<mutex>.
390 Make the template<> prefix for wait() go away by supplying only its return
391 type 'void'; make the 'typename LockType' template argument go away by
392 supplying only the following 'typename'.]
393[condition_variable_x condition_variable..std::unique_lock< mutex >..void..typename]
394
395[endsect]