BDE 4.39.x Production Release
Loading...
Searching...
No Matches
bslmt_condition.h
Go to the documentation of this file.
1/// @file bslmt_condition.h
2///
3/// The content of this file has been pre-processed for Doxygen.
4///
5
6
7// bslmt_condition.h -*-C++-*-
8#ifndef INCLUDED_BSLMT_CONDITION
9#define INCLUDED_BSLMT_CONDITION
10
11#include <bsls_ident.h>
12BSLS_IDENT("$Id: $")
13
14/// @defgroup bslmt_condition bslmt_condition
15/// @brief Provide a portable, efficient condition variable.
16/// @addtogroup bsl
17/// @{
18/// @addtogroup bslmt
19/// @{
20/// @addtogroup bslmt_condition
21/// @{
22///
23/// <h1> Outline </h1>
24/// * <a href="#bslmt_condition-purpose"> Purpose</a>
25/// * <a href="#bslmt_condition-classes"> Classes </a>
26/// * <a href="#bslmt_condition-description"> Description </a>
27/// * <a href="#bslmt_condition-supported-clock-types"> Supported Clock-Types </a>
28/// * <a href="#bslmt_condition-usage"> Usage </a>
29/// * <a href="#bslmt_condition-example-1-basic-usage"> Example 1: Basic Usage </a>
30///
31/// # Purpose {#bslmt_condition-purpose}
32/// Provide a portable, efficient condition variable.
33///
34/// # Classes {#bslmt_condition-classes}
35///
36/// - bslmt::Condition: portable intra-process signaling mechanism
37///
38/// @see bslmt_mutex
39///
40/// # Description {#bslmt_condition-description}
41/// The `bslmt::Condition` class provided by this component
42/// implements the concept of a *condition* *variable*, enabling multiple
43/// threads to communicate information about the state of shared data. A
44/// condition variable is a signaling mechanism associated with a mutex, which
45/// in turn protects a data invariant. A condition variable enables threads to
46/// wait for a predicate (i.e., logical expression) to become true, and to
47/// communicate to other threads that the predicate might be true.
48///
49/// One or more threads can wait efficiently on a condition variable, either
50/// indefinitely or until some *absolute* time, by invoking one of the following
51/// methods of `bslmt::Condition`:
52/// @code
53/// int wait(bslmt::Mutex *mutex);
54/// int timedWait(bslmt::Mutex *mutex, const bsls::TimeInterval& absTime);
55/// @endcode
56/// The caller must lock the mutex before invoking these functions. The
57/// `bslmt::Condition` atomically releases the lock and waits, thereby
58/// preventing other threads from changing the predicate after the lock is
59/// released, but before the thread begins to wait. The `bslmt` package
60/// guarantees that this lock will be reacquired before returning from a call to
61/// the `wait` and `timedWait` methods, unless an error occurs.
62///
63/// When invoking the `timedWait` method, clients must specify, via the
64/// parameter `absTime`, a timeout after which the call will return even if the
65/// condition is not signaled. `absTime` is expressed as a `bsls::TimeInterval`
66/// object that holds an *absolute* time according to the clock type the
67/// `bslmt::Condition` object is constructed with (the default clock is
68/// `bsls::SystemClockType::e_REALTIME`). Clients should use the
69/// `bsls::SystemTime::now(clockType)` utility method to obtain the current
70/// time.
71///
72/// Other threads can indicate that the predicate is true by signaling or
73/// broadcasting the same `bslmt::Condition` object. A broadcast wakes up all
74/// waiting threads, whereas a signal wakes only one thread. The client has no
75/// control over which thread will be signaled if multiple threads are waiting:
76/// @code
77/// void signal();
78/// void broadcast();
79/// @endcode
80/// A thread waiting on a condition variable may be signaled (i.e., the thread
81/// may wake up without an error), but find that the predicate is still false.
82/// This situation can arise for a few reasons: spurious wakeups produced by the
83/// operating system, intercepted wakeups, and loose predicates. Therefore, a
84/// waiting thread should always check the predicate *after* (as well as before)
85/// the call to the `wait` function.
86///
87/// ## Supported Clock-Types {#bslmt_condition-supported-clock-types}
88///
89///
90/// `bsls::SystemClockType` supplies the enumeration indicating the system clock
91/// on which timeouts supplied to other methods should be based. If the clock
92/// type indicated at construction is `bsls::SystemClockType::e_REALTIME`, the
93/// `absTime` argument passed to the `timedWait` method should be expressed as
94/// an *absolute* offset since 00:00:00 UTC, January 1, 1970 (which matches the
95/// epoch used in `bsls::SystemTime::now(bsls::SystemClockType::e_REALTIME)`.
96/// If the clock type indicated at construction is
97/// `bsls::SystemClockType::e_MONOTONIC`, the `absTime` argument passed to the
98/// `timedWait` method should be expressed as an *absolute* offset since the
99/// epoch of this clock (which matches the epoch used in
100/// `bsls::SystemTime::now(bsls::SystemClockType::e_MONOTONIC)`.
101///
102/// ## Usage {#bslmt_condition-usage}
103///
104///
105/// This section illustrates intended use of this component.
106///
107/// ### Example 1: Basic Usage {#bslmt_condition-example-1-basic-usage}
108///
109///
110/// Suppose we have a `bslmt::Condition` object, `condition`, and a boolean
111/// predicate associated with `condition` (represented here as a free function
112/// that returns a `bool` value):
113/// @code
114/// /// Return `true` if the invariant holds for `condition`, and `false`
115/// /// otherwise.
116/// bool predicate()
117/// {
118/// return true;
119/// }
120/// @endcode
121/// The following usage pattern should always be followed:
122/// @code
123/// // ...
124///
125/// bslmt::Condition condition;
126/// bslmt::Mutex mutex;
127///
128/// mutex.lock();
129/// while (false == predicate()) {
130/// condition.wait(&mutex);
131/// }
132///
133/// // Modify shared resources and adjust the predicate here.
134///
135/// mutex.unlock();
136///
137/// // ...
138/// @endcode
139/// The usage pattern for a timed wait is similar, but has extra branches to
140/// handle a timeout:
141/// @code
142/// // ...
143///
144/// enum { e_TIMED_OUT = -1 };
145/// bsls::TimeInterval absTime = bsls::SystemTime::nowRealtimeClock();
146///
147/// // Advance 'absTime' to some delta into the future here.
148///
149/// mutex.lock();
150/// while (false == predicate()) {
151/// const int status = condition.timedWait(&mutex, absTime);
152/// if (e_TIMED_OUT == status) {
153/// break;
154/// }
155/// }
156///
157/// if (false == predicate()) {
158/// // The wait timed out and `predicate` returned `false`. Perform
159/// // timeout logic here.
160///
161/// // ...
162/// }
163/// else {
164/// // The condition variable was either signaled or timed out and
165/// // `predicate` returned `true`. Modify shared resources and adjust
166/// // predicate here.
167///
168/// // ...
169/// }
170/// mutex.unlock();
171///
172/// // ...
173/// @endcode
174/// @}
175/** @} */
176/** @} */
177
178/** @addtogroup bsl
179 * @{
180 */
181/** @addtogroup bslmt
182 * @{
183 */
184/** @addtogroup bslmt_condition
185 * @{
186 */
187
188#include <bslscm_version.h>
189
192#include <bslmt_platform.h>
193
194#include <bsls_assert.h>
195#include <bsls_libraryfeatures.h>
196#include <bsls_timeinterval.h>
197#include <bsls_systemclocktype.h>
198
199#ifdef BSLS_LIBRARYFEATURES_HAS_CPP11_BASELINE_LIBRARY
200#include <bslmt_chronoutil.h>
201
202#include <bsl_chrono.h>
203#endif
204
205
206namespace bslmt {
207
208template <class THREAD_POLICY>
210
211class Mutex;
212
213 // ===============
214 // class Condition
215 // ===============
216
217/// This `class` implements a portable inter-thread signaling primitive.
218///
219/// See @ref bslmt_condition
221
222 // DATA
223 ConditionImpl<Platform::ThreadPolicy> d_imp; // platform-specific
224 // implementation
225
226 private:
227 // NOT IMPLEMENTED
228 Condition(const Condition&);
229 Condition& operator=(const Condition&);
230
231 public:
232 // TYPES
233
234 /// The value `timedWait` returns when a timeout occurs.
236
237 // CREATORS
238
239 /// Create a condition variable object. Optionally specify a
240 /// `clockType` indicating the type of the system clock against which
241 /// the `bsls::TimeInterval` `absTime` timeouts passed to the
242 /// `timedWait` method are to be interpreted (see {Supported
243 /// Clock-Types} in the component-level documentation). If `clockType`
244 /// is not specified then the realtime system clock is used. This
245 /// method does not return normally unless there are sufficient system
246 /// resources to construct the object.
247 explicit
250
251#ifdef BSLS_LIBRARYFEATURES_HAS_CPP11_BASELINE_LIBRARY
252 /// Create a condition variable object. Use the realtime system clock
253 /// as the clock against which the `absTime` timeouts passed to the
254 /// `timedWait` methods are interpreted (see {Supported Clock-Types} in
255 /// the component-level documentation). This method does not return
256 /// normally unless there are sufficient system resources to construct
257 /// the object.
258 explicit
259 Condition(const bsl::chrono::system_clock&);
260
261 /// Create a condition variable object. Use the monotonic system clock
262 /// as the clock against which the `absTime` timeouts passed to the
263 /// `timedWait` methods are interpreted (see {Supported Clock-Types} in
264 /// the component-level documentation). This method does not return
265 /// normally unless there are sufficient system resources to construct
266 /// the object.
267 explicit
268 Condition(const bsl::chrono::steady_clock&);
269#endif
270
271 /// Destroy this condition variable object.
272 ~Condition();
273
274 // MANIPULATORS
275
276 /// Signal this condition variable object by waking up *all* threads
277 /// that are currently waiting on this condition. If there are no
278 /// threads waiting on this condition, this method has no effect.
279 void broadcast();
280
281 /// Signal this condition variable object by waking up a single thread
282 /// that is currently waiting on this condition. If there are no
283 /// threads waiting on this condition, this method has no effect.
284 void signal();
285
286 /// Atomically unlock the specified `mutex` and suspend execution of the
287 /// current thread until this condition object is "signaled" (i.e., one
288 /// of the `signal` or `broadcast` methods is invoked on this object) or
289 /// until the specified `absTime` timeout expires, then re-acquire a
290 /// lock on the `mutex`. `absTime` is an *absolute* time represented as
291 /// an interval from some epoch, which is determined by the clock
292 /// indicated at construction (see {Supported Clock-Types} in the
293 /// component-level documentation), and is the earliest time at which
294 /// the timeout may occur. The `mutex` remains locked by the calling
295 /// thread upon returning from this function. Return 0 on success, and
296 /// `e_TIMED_OUT` on timeout. Any other value indicates that an error
297 /// has occurred. After an error, the condition may be destroyed, but
298 /// any other use has undefined behavior.
299 ///
300 /// \pre The behavior is undefined unless `mutex` is locked by the calling thread prior to calling this method.
301 ///
302 /// \note Note that spurious wakeups are rare but possible, i.e.,
303 /// this method may succeed (return 0) and return control to the thread
304 /// without the condition object being signaled. Also note that the
305 /// actual time of the timeout depends on many factors including system
306 /// scheduling and system timer resolution, and may be significantly
307 /// later than the time requested.
308 int timedWait(Mutex *mutex, const bsls::TimeInterval& absTime);
309
310#ifdef BSLS_LIBRARYFEATURES_HAS_CPP11_BASELINE_LIBRARY
311 /// Atomically unlock the specified `mutex` and suspend execution of the
312 /// current thread until this condition object is "signaled" (i.e., one
313 /// of the `signal` or `broadcast` methods is invoked on this object) or
314 /// until the specified `absTime` timeout expires, then re-acquire a
315 /// lock on the `mutex`. `absTime` is an *absolute* time represented as
316 /// an interval from some epoch, which is determined by the clock
317 /// associated with the time point, and is the earliest time at which
318 /// the timeout may occur. The `mutex` remains locked by the calling
319 /// thread upon returning from this function. Return 0 on success, and
320 /// `e_TIMED_OUT` on timeout. Any other value indicates that an error
321 /// has occurred. After an error, the condition may be destroyed, but
322 /// any other use has undefined behavior.
323 ///
324 /// \pre The behavior is undefined unless `mutex` is locked by the calling thread prior to calling this method.
325 ///
326 /// \note Note that spurious wakeups are rare but possible, i.e.,
327 /// this method may succeed (return 0) and return control to the thread
328 /// without the condition object being signaled. Also note that the
329 /// actual time of the timeout depends on many factors including system
330 /// scheduling and system timer resolution, and may be significantly
331 /// later than the time requested. Also note that the lock on `mutex`
332 /// may be released and reacquired more than once before this method
333 /// returns.
334 template <class CLOCK, class DURATION>
335 int timedWait(Mutex *mutex,
336 const bsl::chrono::time_point<CLOCK, DURATION>& absTime);
337#endif
338
339 /// Atomically unlock the specified `mutex` and suspend execution of the
340 /// current thread until this condition object is "signaled" (i.e.,
341 /// either `signal` or `broadcast` is invoked on this object in another
342 /// thread), then re-acquire a lock on the `mutex`. Return 0 on
343 /// success, and a non-zero value otherwise. Spurious wakeups are rare
344 /// but possible; i.e., this method may succeed (return 0), and return
345 /// control to the thread without the condition object being signaled.
346 ///
347 /// \pre The behavior is undefined unless `mutex` is locked by the calling thread prior to calling this method.
348 ///
349 /// \note Note that `mutex` remains
350 /// locked by the calling thread upon return from this function.
351 int wait(Mutex *mutex);
352
353 // ACCESSORS
354
355 /// Return the clock type used for timeouts.
357};
358
359
360// ============================================================================
361// INLINE DEFINITIONS
362// ============================================================================
363
364 // ---------------
365 // class Condition
366 // ---------------
367
368// CREATORS
369inline
370Condition::Condition(bsls::SystemClockType::Enum clockType)
371: d_imp(clockType)
372{
373}
374
375#ifdef BSLS_LIBRARYFEATURES_HAS_CPP11_BASELINE_LIBRARY
376inline
377Condition::Condition(const bsl::chrono::system_clock&)
378: d_imp(bsls::SystemClockType::e_REALTIME)
379{
380}
381
382inline
383Condition::Condition(const bsl::chrono::steady_clock&)
384: d_imp(bsls::SystemClockType::e_MONOTONIC)
385{
386}
387#endif
388
389inline
393
394// MANIPULATORS
395inline
397{
398 d_imp.broadcast();
399}
400
401inline
403{
404 d_imp.signal();
405}
406
407inline
409 const bsls::TimeInterval& absTime)
410{
411 BSLS_ASSERT_SAFE(mutex);
412
413 return d_imp.timedWait(mutex, absTime);
414}
415
416#ifdef BSLS_LIBRARYFEATURES_HAS_CPP11_BASELINE_LIBRARY
417template <class CLOCK, class DURATION>
418inline
420 Mutex *mutex,
421 const bsl::chrono::time_point<CLOCK, DURATION>& absTime)
422{
423 BSLS_ASSERT_SAFE(mutex);
424
425 return ChronoUtil::timedWait(this, mutex, absTime);
426}
427#endif
428
429inline
431{
432 BSLS_ASSERT_SAFE(mutex);
433
434 return d_imp.wait(mutex);
435}
436
437// ACCESSORS
438inline
440{
441 return d_imp.clockType();
442}
443
444} // close package namespace
445
446
447#endif
448
449// ----------------------------------------------------------------------------
450// Copyright 2023 Bloomberg Finance L.P.
451//
452// Licensed under the Apache License, Version 2.0 (the "License");
453// you may not use this file except in compliance with the License.
454// You may obtain a copy of the License at
455//
456// http://www.apache.org/licenses/LICENSE-2.0
457//
458// Unless required by applicable law or agreed to in writing, software
459// distributed under the License is distributed on an "AS IS" BASIS,
460// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
461// See the License for the specific language governing permissions and
462// limitations under the License.
463// ----------------------------- END-OF-FILE ----------------------------------
464
465/** @} */
466/** @} */
467/** @} */
Definition bslmt_condition.h:209
Definition bslmt_condition.h:220
int timedWait(Mutex *mutex, const bsls::TimeInterval &absTime)
Definition bslmt_condition.h:408
int wait(Mutex *mutex)
Definition bslmt_condition.h:430
void signal()
Definition bslmt_condition.h:402
bsls::SystemClockType::Enum clockType() const
Return the clock type used for timeouts.
Definition bslmt_condition.h:439
void broadcast()
Definition bslmt_condition.h:396
~Condition()
Destroy this condition variable object.
Definition bslmt_condition.h:390
@ e_TIMED_OUT
Definition bslmt_condition.h:235
Definition bslmt_mutex.h:317
Definition bsls_timeinterval.h:307
#define BSLS_ASSERT_SAFE(X)
Definition bsls_assert.h:1917
#define BSLS_IDENT(str)
BSLS_IDENT() - insert string into .comment binary segment (if supported)
Definition bsls_ident.h:238
Definition bslmt_barrier.h:344
Definition bdlt_iso8601util.h:707
Enum
Definition bsls_systemclocktype.h:119
@ e_REALTIME
Definition bsls_systemclocktype.h:122