BDE 4.39.x Production Release
Loading...
Searching...
No Matches
bslmt_sluice.h
Go to the documentation of this file.
1/// @file bslmt_sluice.h
2///
3/// The content of this file has been pre-processed for Doxygen.
4///
5
6
7// bslmt_sluice.h -*-C++-*-
8#ifndef INCLUDED_BSLMT_SLUICE
9#define INCLUDED_BSLMT_SLUICE
10
11#include <bsls_ident.h>
12BSLS_IDENT("$Id: $")
13
14/// @defgroup bslmt_sluice bslmt_sluice
15/// @brief Provide a "sluice" class.
16/// @addtogroup bsl
17/// @{
18/// @addtogroup bslmt
19/// @{
20/// @addtogroup bslmt_sluice
21/// @{
22///
23/// <h1> Outline </h1>
24/// * <a href="#bslmt_sluice-purpose"> Purpose</a>
25/// * <a href="#bslmt_sluice-classes"> Classes </a>
26/// * <a href="#bslmt_sluice-description"> Description </a>
27/// * <a href="#bslmt_sluice-supported-clock-types"> Supported Clock-Types </a>
28/// * <a href="#bslmt_sluice-usage"> Usage </a>
29/// * <a href="#bslmt_sluice-example-1-basic-usage"> Example 1: Basic Usage </a>
30///
31/// # Purpose {#bslmt_sluice-purpose}
32/// Provide a "sluice" class.
33///
34/// # Classes {#bslmt_sluice-classes}
35///
36/// - bslmt::Sluice: thread-aware sluice class
37///
38/// @see bslmt_conditionimpl_win32
39///
40/// # Description {#bslmt_sluice-description}
41/// This component provides a "sluice" class, `bslmt::Sluice`. A
42/// sluice is useful for controlling the release of threads from a common
43/// synchronization point. One or more threads may "enter" a `bslmt::Sluice`
44/// object (via the `enter` method), and then wait to be released (via either
45/// the `wait` or `timedWait` method). Either one waiting thread (via the
46/// `signalOne` method), or all waiting threads (via the `signalAll` method),
47/// may be signaled for release. In either case, `bslmt::Sluice` provides a
48/// guarantee against starvation; newly-entering threads will not indefinitely
49/// prevent threads that previously entered from being signaled.
50///
51/// ## Supported Clock-Types {#bslmt_sluice-supported-clock-types}
52///
53///
54/// `bsls::SystemClockType` supplies the enumeration indicating the system clock
55/// on which timeouts supplied to other methods should be based. If the clock
56/// type indicated at construction is `bsls::SystemClockType::e_REALTIME`, the
57/// `absTime` argument passed to the `timedWait` method should be expressed as
58/// an *absolute* offset since 00:00:00 UTC, January 1, 1970 (which matches the
59/// epoch used in `bsls::SystemTime::now(bsls::SystemClockType::e_REALTIME)`.
60/// If the clock type indicated at construction is
61/// `bsls::SystemClockType::e_MONOTONIC`, the `absTime` argument passed to the
62/// `timedWait` method should be expressed as an *absolute* offset since the
63/// epoch of this clock (which matches the epoch used in
64/// `bsls::SystemTime::now(bsls::SystemClockType::e_MONOTONIC)`.
65///
66/// ## Usage {#bslmt_sluice-usage}
67///
68///
69/// This section illustrates intended use of this component.
70///
71/// ### Example 1: Basic Usage {#bslmt_sluice-example-1-basic-usage}
72///
73///
74/// `bslmt::Sluice` is intended to be used to implement other synchronization
75/// mechanisms. In particular, the functionality provided by `bslmt::Sluice` is
76/// useful for implementing a condition variable:
77/// @code
78/// /// This class implements a condition variable based on `bslmt::Sluice`.
79/// class MyCondition {
80///
81/// // DATA
82/// bslmt::Sluice d_waitSluice; // sluice object
83///
84/// public:
85/// // MANIPULATORS
86/// void wait(bslmt::Mutex *mutex)
87/// {
88/// const void *token = d_waitSluice.enter();
89/// mutex->unlock();
90/// d_waitSluice.wait(token);
91/// mutex->lock();
92/// }
93///
94/// void signal()
95/// {
96/// d_waitSluice.signalOne();
97/// }
98///
99/// void broadcast()
100/// {
101/// d_waitSluice.signalAll();
102/// }
103/// };
104/// @endcode
105/// @}
106/** @} */
107/** @} */
108
109/** @addtogroup bsl
110 * @{
111 */
112/** @addtogroup bslmt
113 * @{
114 */
115/** @addtogroup bslmt_sluice
116 * @{
117 */
118
119#include <bslscm_version.h>
120
121#include <bslmt_lockguard.h>
122#include <bslmt_mutex.h>
123#include <bslmt_timedsemaphore.h>
124
125#include <bsls_assert.h>
126#include <bsls_libraryfeatures.h>
127#include <bsls_systemclocktype.h>
128
129#include <bslma_allocator.h>
130
131#ifdef BSLS_LIBRARYFEATURES_HAS_CPP11_BASELINE_LIBRARY
132#include <bslmt_chronoutil.h>
133
134#include <bsl_chrono.h>
135#endif
136
137
138namespace bslmt {
139
140 // ============
141 // class Sluice
142 // ============
143
144/// This class controls the release of threads from a common synchronization
145/// point. One or more threads may "enter" a `Sluice` object, and then wait
146/// to be released. Either one waiting thread (via the `signalOne` method),
147/// or all waiting threads (via the `signalAll` method), may be signaled for
148/// release. In any case, `Sluice` provides a guarantee against starvation.
149///
150/// See @ref bslmt_sluice
151class Sluice {
152
153 private:
154 // PRIVATE TYPES
155
156 /// This object represents one "generation" in a sluice. A generation
157 /// begins when a thread enters the sluice, and ends (ceases accepting
158 /// new entering threads) when `signalOne` or `signalAll` is invoked.
159 /// The last thread in the generation to invoke `wait` is responsible
160 /// for returning the descriptor to the pool.
161 ///
162 /// See @ref bslmt_sluice
163 struct GenerationDescriptor {
164
165 // DATA
166 int d_numThreads; // number of threads entered, but
167 // not yet finished waiting
168
169 int d_numSignaled; // number of threads signaled,
170 // but not yet finished waiting
171
172 TimedSemaphore d_sema; // semaphore on which to wait
173
174 GenerationDescriptor *d_next; // pointer to the next free
175 // descriptor in the pool
176
177 // CREATORS
178
179 /// Create a generation descriptor object with the specified
180 /// `clockType`.
181 explicit GenerationDescriptor(bsls::SystemClockType::Enum clockType);
182 };
183
184 // DATA
185 Mutex d_mutex; // for synchronizing access to
186 // data members
187
188 GenerationDescriptor *d_signaledGeneration; // generation in which at
189 // least one, but not all,
190 // threads have been signaled
191
192 GenerationDescriptor *d_pendingGeneration; // generation in which no
193 // threads have been signaled
194 // yet
195
196 GenerationDescriptor *d_descriptorPool; // pool of available
197 // generation descriptors
198
200 d_clockType; // the type of clock used for
201 // 'absTime' in 'timedWait'
202
203 bslma::Allocator *d_allocator_p; // memory allocator (held, not
204 // owned)
205
206 private:
207 // NOT IMPLEMENTED
208 Sluice(const Sluice&);
209 Sluice& operator=(const Sluice&);
210
211 public:
212 // TYPES
213
214 /// The value `timedWait` returns when a timeout occurs.
216
217 // CREATORS
218
219 /// Create a sluice. Optionally specify a `clockType` indicating the
220 /// type of the system clock against which the `bsls::TimeInterval`
221 /// `absTime` timeouts passed to the `timedWait` method are to be
222 /// interpreted (see {Supported Clock-Types} in the component
223 /// documentation). If `clockType` is not specified then the realtime
224 /// system clock is used. Optionally specify a `basicAllocator` used to
225 /// supply memory. If `basicAllocator` is 0, the currently installed
226 /// default allocator is used.
227 explicit
228 Sluice(bslma::Allocator *basicAllocator = 0);
229 explicit
231 bslma::Allocator *basicAllocator = 0);
232
233#ifdef BSLS_LIBRARYFEATURES_HAS_CPP11_BASELINE_LIBRARY
234 /// Create a sluice. Use the realtime system clock as the clock against
235 /// which the `absTime` timeouts passed to the `timedWait` methods are
236 /// interpreted (see {Supported Clock-Types} in the component-level
237 /// documentation). Optionally specify a `basicAllocator` used to
238 /// supply memory. If `basicAllocator` is 0, the currently installed
239 /// default allocator is used.
240 explicit
241 Sluice(const bsl::chrono::system_clock&,
242 bslma::Allocator *basicAllocator = 0);
243
244 /// Create a sluice. Use the monotonic system clock as the clock
245 /// against which the `absTime` timeouts passed to the `timedWait`
246 /// methods are interpreted (see {Supported Clock-Types} in the
247 /// component-level documentation). Optionally specify a
248 /// `basicAllocator` used to supply memory. If `basicAllocator` is 0,
249 /// the currently installed default allocator is used.
250 explicit
251 Sluice(const bsl::chrono::steady_clock&,
252 bslma::Allocator *basicAllocator = 0);
253#endif
254
255 /// Destroy this sluice.
257
258 // MANIPULATORS
259
260 /// Enter this sluice, and return the token on which the calling thread must subsequently wait.
261 ///
262 /// \pre The behavior is undefined unless `wait` or
263 /// `timedWait` is invoked with the token before this sluice is
264 /// destroyed.
265 const void *enter();
266
267 /// Signal all threads that have entered this sluice and have not yet
268 /// been released.
269 void signalAll();
270
271 /// Signal one thread that has entered this sluice and has not yet been
272 /// released.
273 void signalOne();
274
275 /// Wait for the specified `token` to be signaled, or until the
276 /// specified `absTime` timeout expires. `absTime` is an *absolute*
277 /// time represented as an interval from some epoch, which is determined
278 /// by the clock indicated at construction (see {Supported Clock-Types}
279 /// in the component-level documentation). Return 0 on success, and
280 /// `e_TIMED_OUT` on timeout. Any other value indicates that an error
281 /// has occurred. Errors are unrecoverable. After an error, the sluice
282 /// may be destroyed, but any other use has undefined behavior. The
283 /// `token` is released whether or not a timeout occurred.
284 ///
285 /// \pre The behavior is undefined unless `token` was obtained from a call to `enter` by
286 /// this thread, and was not subsequently released (via a call to
287 /// `timedWait` or `wait`).
288 int timedWait(const void *token, const bsls::TimeInterval& absTime);
289
290#ifdef BSLS_LIBRARYFEATURES_HAS_CPP11_BASELINE_LIBRARY
291 /// Wait for the specified `token` to be signaled, or until the
292 /// specified `absTime` timeout expires. `absTime` is an *absolute*
293 /// time represented as an interval from some epoch, which is determined
294 /// by the clock associated with the time point. Return 0 on success,
295 /// and `e_TIMED_OUT` on timeout. Any other value indicates that an
296 /// error has occurred. Errors are unrecoverable. After an error, the
297 /// sluice may be destroyed, but any other use has undefined behavior.
298 /// The `token` is released whether or not a timeout occurred.
299 ///
300 /// \pre The behavior is undefined unless `token` was obtained from a call to
301 /// `enter` by this thread, and was not subsequently released (via a
302 /// call to `timedWait` or `wait`).
303 template <class CLOCK, class DURATION>
304 int timedWait(const void *token,
305 const bsl::chrono::time_point<CLOCK, DURATION>& absTime);
306#endif
307
308 /// Wait for the specified `token` to be signaled, and release the `token`.
309 ///
310 /// \pre The behavior is undefined unless `token` was obtained from
311 /// a call to `enter` by this thread, and was not subsequently released
312 /// (via a call to `timedWait` or `wait`).
313 void wait(const void *token);
314
315 // ACCESSORS
316
317 /// Return the clock type used for timeouts.
319};
320
321// ============================================================================
322// INLINE DEFINITIONS
323// ============================================================================
324
325 // ------------
326 // class Sluice
327 // ------------
328
329#ifdef BSLS_LIBRARYFEATURES_HAS_CPP11_BASELINE_LIBRARY
330// MANIPULATORS
331template <class CLOCK, class DURATION>
332int Sluice::timedWait(const void *token,
333 const bsl::chrono::time_point<CLOCK, DURATION>& absTime)
334{
335
336 GenerationDescriptor *g =
337 static_cast<GenerationDescriptor *>(const_cast<void *>(token));
338
339 for (;;) {
340 int rc = g->d_sema.timedWait(absTime);
341
342 LockGuard<Mutex> lock(&d_mutex);
343
344 if (g->d_numSignaled) {
345 BSLS_ASSERT(d_pendingGeneration != g);
346
347 --g->d_numSignaled;
348
349 rc = 0;
350 }
351 else if (0 == rc) {
352 continue;
353 }
354
355 const int numThreads = --g->d_numThreads;
356
357 if (0 == numThreads) {
358 // The last thread is responsible for cleanup.
359
360 if (d_signaledGeneration == g) {
361 BSLS_ASSERT(0 != rc);
362 d_signaledGeneration = 0;
363 }
364
365 if (d_pendingGeneration == g) {
366 BSLS_ASSERT(0 != rc);
367 d_pendingGeneration = 0;
368 }
369
370 g->d_next = d_descriptorPool;
371 d_descriptorPool = g;
372 }
373 return rc; // RETURN
374 }
375}
376#endif
377
378// ACCESSORS
379inline
381{
382 return d_clockType;
383}
384
385} // close package namespace
386
387
388#endif
389
390// ----------------------------------------------------------------------------
391// Copyright 2015 Bloomberg Finance L.P.
392//
393// Licensed under the Apache License, Version 2.0 (the "License");
394// you may not use this file except in compliance with the License.
395// You may obtain a copy of the License at
396//
397// http://www.apache.org/licenses/LICENSE-2.0
398//
399// Unless required by applicable law or agreed to in writing, software
400// distributed under the License is distributed on an "AS IS" BASIS,
401// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
402// See the License for the specific language governing permissions and
403// limitations under the License.
404// ----------------------------- END-OF-FILE ----------------------------------
405
406/** @} */
407/** @} */
408/** @} */
Definition bslma_allocator.h:545
Definition bslmt_lockguard.h:234
Definition bslmt_mutex.h:317
Definition bslmt_sluice.h:151
void wait(const void *token)
int timedWait(const void *token, const bsls::TimeInterval &absTime)
bsls::SystemClockType::Enum clockType() const
Return the clock type used for timeouts.
Definition bslmt_sluice.h:380
Sluice(bsls::SystemClockType::Enum clockType, bslma::Allocator *basicAllocator=0)
const void * enter()
@ e_TIMED_OUT
Definition bslmt_sluice.h:215
~Sluice()
Destroy this sluice.
void signalAll()
void signalOne()
Sluice(bslma::Allocator *basicAllocator=0)
Definition bslmt_timedsemaphore.h:222
@ e_TIMED_OUT
Definition bslmt_timedsemaphore.h:236
Definition bsls_timeinterval.h:307
#define BSLS_ASSERT(X)
Definition bsls_assert.h:1976
#define BSLS_IDENT(str)
BSLS_IDENT() - insert string into .comment binary segment (if supported)
Definition bsls_ident.h:238
Definition bslmt_barrier.h:344
Enum
Definition bsls_systemclocktype.h:119