BDE 4.14.0 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 // NOT IMPLEMENTED
227 Condition(const Condition&);
228 Condition& operator=(const Condition&);
229
230 public:
231 // TYPES
232
233 /// The value `timedWait` returns when a timeout occurs.
235
236 // CREATORS
237
238 /// Create a condition variable object. Optionally specify a
239 /// `clockType` indicating the type of the system clock against which
240 /// the `bsls::TimeInterval` `absTime` timeouts passed to the
241 /// `timedWait` method are to be interpreted (see {Supported
242 /// Clock-Types} in the component-level documentation). If `clockType`
243 /// is not specified then the realtime system clock is used. This
244 /// method does not return normally unless there are sufficient system
245 /// resources to construct the object.
246 explicit
249
250#ifdef BSLS_LIBRARYFEATURES_HAS_CPP11_BASELINE_LIBRARY
251 /// Create a condition variable object. Use the realtime system clock
252 /// as the clock against which the `absTime` timeouts passed to the
253 /// `timedWait` methods are interpreted (see {Supported Clock-Types} in
254 /// the component-level documentation). This method does not return
255 /// normally unless there are sufficient system resources to construct
256 /// the object.
257 explicit
258 Condition(const bsl::chrono::system_clock&);
259
260 /// Create a condition variable object. Use the monotonic system clock
261 /// as the clock against which the `absTime` timeouts passed to the
262 /// `timedWait` methods are interpreted (see {Supported Clock-Types} in
263 /// the component-level documentation). This method does not return
264 /// normally unless there are sufficient system resources to construct
265 /// the object.
266 explicit
267 Condition(const bsl::chrono::steady_clock&);
268#endif
269
270 /// Destroy this condition variable object.
271 ~Condition();
272
273 // MANIPULATORS
274
275 /// Signal this condition variable object by waking up *all* threads
276 /// that are currently waiting on this condition. If there are no
277 /// threads waiting on this condition, this method has no effect.
278 void broadcast();
279
280 /// Signal this condition variable object by waking up a single thread
281 /// that is currently waiting on this condition. If there are no
282 /// threads waiting on this condition, this method has no effect.
283 void signal();
284
285 /// Atomically unlock the specified `mutex` and suspend execution of the
286 /// current thread until this condition object is "signaled" (i.e., one
287 /// of the `signal` or `broadcast` methods is invoked on this object) or
288 /// until the specified `absTime` timeout expires, then re-acquire a
289 /// lock on the `mutex`. `absTime` is an *absolute* time represented as
290 /// an interval from some epoch, which is determined by the clock
291 /// indicated at construction (see {Supported Clock-Types} in the
292 /// component-level documentation), and is the earliest time at which
293 /// the timeout may occur. The `mutex` remains locked by the calling
294 /// thread upon returning from this function. Return 0 on success, and
295 /// `e_TIMED_OUT` on timeout. Any other value indicates that an error
296 /// has occurred. After an error, the condition may be destroyed, but
297 /// any other use has undefined behavior. The behavior is undefined
298 /// unless `mutex` is locked by the calling thread prior to calling this
299 /// method. Note that spurious wakeups are rare but possible, i.e.,
300 /// this method may succeed (return 0) and return control to the thread
301 /// without the condition object being signaled. Also note that the
302 /// actual time of the timeout depends on many factors including system
303 /// scheduling and system timer resolution, and may be significantly
304 /// later than the time requested.
305 int timedWait(Mutex *mutex, const bsls::TimeInterval& absTime);
306
307#ifdef BSLS_LIBRARYFEATURES_HAS_CPP11_BASELINE_LIBRARY
308 /// Atomically unlock the specified `mutex` and suspend execution of the
309 /// current thread until this condition object is "signaled" (i.e., one
310 /// of the `signal` or `broadcast` methods is invoked on this object) or
311 /// until the specified `absTime` timeout expires, then re-acquire a
312 /// lock on the `mutex`. `absTime` is an *absolute* time represented as
313 /// an interval from some epoch, which is determined by the clock
314 /// associated with the time point, and is the earliest time at which
315 /// the timeout may occur. The `mutex` remains locked by the calling
316 /// thread upon returning from this function. Return 0 on success, and
317 /// `e_TIMED_OUT` on timeout. Any other value indicates that an error
318 /// has occurred. After an error, the condition may be destroyed, but
319 /// any other use has undefined behavior. The behavior is undefined
320 /// unless `mutex` is locked by the calling thread prior to calling this
321 /// method. Note that spurious wakeups are rare but possible, i.e.,
322 /// this method may succeed (return 0) and return control to the thread
323 /// without the condition object being signaled. Also note that the
324 /// actual time of the timeout depends on many factors including system
325 /// scheduling and system timer resolution, and may be significantly
326 /// later than the time requested. Also note that the lock on `mutex`
327 /// may be released and reacquired more than once before this method
328 /// returns.
329 template <class CLOCK, class DURATION>
330 int timedWait(Mutex *mutex,
331 const bsl::chrono::time_point<CLOCK, DURATION>& absTime);
332#endif
333
334 /// Atomically unlock the specified `mutex` and suspend execution of the
335 /// current thread until this condition object is "signaled" (i.e.,
336 /// either `signal` or `broadcast` is invoked on this object in another
337 /// thread), then re-acquire a lock on the `mutex`. Return 0 on
338 /// success, and a non-zero value otherwise. Spurious wakeups are rare
339 /// but possible; i.e., this method may succeed (return 0), and return
340 /// control to the thread without the condition object being signaled.
341 /// The behavior is undefined unless `mutex` is locked by the calling
342 /// thread prior to calling this method. Note that `mutex` remains
343 /// locked by the calling thread upon return from this function.
344 int wait(Mutex *mutex);
345
346 // ACCESSORS
347
348 /// Return the clock type used for timeouts.
350};
351
352
353// ============================================================================
354// INLINE DEFINITIONS
355// ============================================================================
356
357 // ---------------
358 // class Condition
359 // ---------------
360
361// CREATORS
362inline
363Condition::Condition(bsls::SystemClockType::Enum clockType)
364: d_imp(clockType)
365{
366}
367
368#ifdef BSLS_LIBRARYFEATURES_HAS_CPP11_BASELINE_LIBRARY
369inline
370Condition::Condition(const bsl::chrono::system_clock&)
371: d_imp(bsls::SystemClockType::e_REALTIME)
372{
373}
374
375inline
376Condition::Condition(const bsl::chrono::steady_clock&)
377: d_imp(bsls::SystemClockType::e_MONOTONIC)
378{
379}
380#endif
381
382inline
386
387// MANIPULATORS
388inline
390{
391 d_imp.broadcast();
392}
393
394inline
396{
397 d_imp.signal();
398}
399
400inline
402 const bsls::TimeInterval& absTime)
403{
404 BSLS_ASSERT_SAFE(mutex);
405
406 return d_imp.timedWait(mutex, absTime);
407}
408
409#ifdef BSLS_LIBRARYFEATURES_HAS_CPP11_BASELINE_LIBRARY
410template <class CLOCK, class DURATION>
411inline
413 Mutex *mutex,
414 const bsl::chrono::time_point<CLOCK, DURATION>& absTime)
415{
416 BSLS_ASSERT_SAFE(mutex);
417
418 return ChronoUtil::timedWait(this, mutex, absTime);
419}
420#endif
421
422inline
424{
425 BSLS_ASSERT_SAFE(mutex);
426
427 return d_imp.wait(mutex);
428}
429
430// ACCESSORS
431inline
433{
434 return d_imp.clockType();
435}
436
437} // close package namespace
438
439
440#endif
441
442// ----------------------------------------------------------------------------
443// Copyright 2023 Bloomberg Finance L.P.
444//
445// Licensed under the Apache License, Version 2.0 (the "License");
446// you may not use this file except in compliance with the License.
447// You may obtain a copy of the License at
448//
449// http://www.apache.org/licenses/LICENSE-2.0
450//
451// Unless required by applicable law or agreed to in writing, software
452// distributed under the License is distributed on an "AS IS" BASIS,
453// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
454// See the License for the specific language governing permissions and
455// limitations under the License.
456// ----------------------------- END-OF-FILE ----------------------------------
457
458/** @} */
459/** @} */
460/** @} */
Definition bslmt_condition.h:209
Definition bslmt_condition.h:220
int timedWait(Mutex *mutex, const bsls::TimeInterval &absTime)
Definition bslmt_condition.h:401
int wait(Mutex *mutex)
Definition bslmt_condition.h:423
void signal()
Definition bslmt_condition.h:395
@ e_TIMED_OUT
Definition bslmt_condition.h:234
bsls::SystemClockType::Enum clockType() const
Return the clock type used for timeouts.
Definition bslmt_condition.h:432
void broadcast()
Definition bslmt_condition.h:389
~Condition()
Destroy this condition variable object.
Definition bslmt_condition.h:383
Definition bslmt_mutex.h:315
Definition bsls_timeinterval.h:301
#define BSLS_ASSERT_SAFE(X)
Definition bsls_assert.h:1762
#define BSLS_IDENT(str)
Definition bsls_ident.h:195
Definition bslmt_barrier.h:344
Definition bdlt_iso8601util.h:691
static int timedWait(PRIMITIVE *primitive, const bsl::chrono::time_point< CLOCK, DURATION > &absTime)
Definition bslmt_chronoutil.h:345
Enum
Definition bsls_systemclocktype.h:117
@ e_REALTIME
Definition bsls_systemclocktype.h:120