BDE 4.14.0 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 struct GenerationDescriptor {
162
163 // DATA
164 int d_numThreads; // number of threads entered, but
165 // not yet finished waiting
166
167 int d_numSignaled; // number of threads signaled,
168 // but not yet finished waiting
169
170 TimedSemaphore d_sema; // semaphore on which to wait
171
172 GenerationDescriptor *d_next; // pointer to the next free
173 // descriptor in the pool
174
175 // CREATORS
176
177 /// Create a generation descriptor object with the specified
178 /// `clockType`.
179 explicit GenerationDescriptor(bsls::SystemClockType::Enum clockType);
180 };
181
182 // DATA
183 Mutex d_mutex; // for synchronizing access to
184 // data members
185
186 GenerationDescriptor *d_signaledGeneration; // generation in which at
187 // least one, but not all,
188 // threads have been signaled
189
190 GenerationDescriptor *d_pendingGeneration; // generation in which no
191 // threads have been signaled
192 // yet
193
194 GenerationDescriptor *d_descriptorPool; // pool of available
195 // generation descriptors
196
198 d_clockType; // the type of clock used for
199 // 'absTime' in 'timedWait'
200
201 bslma::Allocator *d_allocator_p; // memory allocator (held, not
202 // owned)
203
204 private:
205 // NOT IMPLEMENTED
206 Sluice(const Sluice&);
207 Sluice& operator=(const Sluice&);
208
209 public:
210 // TYPES
211
212 /// The value `timedWait` returns when a timeout occurs.
214
215 // CREATORS
216
217 explicit
218 Sluice(bslma::Allocator *basicAllocator = 0);
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
229 bslma::Allocator *basicAllocator = 0);
230
231#ifdef BSLS_LIBRARYFEATURES_HAS_CPP11_BASELINE_LIBRARY
232 /// Create a sluice. Use the realtime system clock as the clock against
233 /// which the `absTime` timeouts passed to the `timedWait` methods are
234 /// interpreted (see {Supported Clock-Types} in the component-level
235 /// documentation). Optionally specify a `basicAllocator` used to
236 /// supply memory. If `basicAllocator` is 0, the currently installed
237 /// default allocator is used.
238 explicit
239 Sluice(const bsl::chrono::system_clock&,
240 bslma::Allocator *basicAllocator = 0);
241
242 /// Create a sluice. Use the monotonic system clock as the clock
243 /// against which the `absTime` timeouts passed to the `timedWait`
244 /// methods are interpreted (see {Supported Clock-Types} in the
245 /// component-level documentation). Optionally specify a
246 /// `basicAllocator` used to supply memory. If `basicAllocator` is 0,
247 /// the currently installed default allocator is used.
248 explicit
249 Sluice(const bsl::chrono::steady_clock&,
250 bslma::Allocator *basicAllocator = 0);
251#endif
252
253 /// Destroy this sluice.
255
256 // MANIPULATORS
257
258 /// Enter this sluice, and return the token on which the calling thread
259 /// must subsequently wait. The behavior is undefined unless `wait` or
260 /// `timedWait` is invoked with the token before this sluice is
261 /// destroyed.
262 const void *enter();
263
264 /// Signal all threads that have entered this sluice and have not yet
265 /// been released.
266 void signalAll();
267
268 /// Signal one thread that has entered this sluice and has not yet been
269 /// released.
270 void signalOne();
271
272 /// Wait for the specified `token` to be signaled, or until the
273 /// specified `absTime` timeout expires. `absTime` is an *absolute*
274 /// time represented as an interval from some epoch, which is determined
275 /// by the clock indicated at construction (see {Supported Clock-Types}
276 /// in the component-level documentation). Return 0 on success, and
277 /// `e_TIMED_OUT` on timeout. Any other value indicates that an error
278 /// has occurred. Errors are unrecoverable. After an error, the sluice
279 /// may be destroyed, but any other use has undefined behavior. The
280 /// `token` is released whether or not a timeout occurred. The behavior
281 /// is undefined unless `token` was obtained from a call to `enter` by
282 /// this thread, and was not subsequently released (via a call to
283 /// `timedWait` or `wait`).
284 int timedWait(const void *token, const bsls::TimeInterval& absTime);
285
286#ifdef BSLS_LIBRARYFEATURES_HAS_CPP11_BASELINE_LIBRARY
287 /// Wait for the specified `token` to be signaled, or until the
288 /// specified `absTime` timeout expires. `absTime` is an *absolute*
289 /// time represented as an interval from some epoch, which is determined
290 /// by the clock associated with the time point. Return 0 on success,
291 /// and `e_TIMED_OUT` on timeout. Any other value indicates that an
292 /// error has occurred. Errors are unrecoverable. After an error, the
293 /// sluice may be destroyed, but any other use has undefined behavior.
294 /// The `token` is released whether or not a timeout occurred. The
295 /// behavior is undefined unless `token` was obtained from a call to
296 /// `enter` by this thread, and was not subsequently released (via a
297 /// call to `timedWait` or `wait`).
298 template <class CLOCK, class DURATION>
299 int timedWait(const void *token,
300 const bsl::chrono::time_point<CLOCK, DURATION>& absTime);
301#endif
302
303 /// Wait for the specified `token` to be signaled, and release the
304 /// `token`. The behavior is undefined unless `token` was obtained from
305 /// a call to `enter` by this thread, and was not subsequently released
306 /// (via a call to `timedWait` or `wait`).
307 void wait(const void *token);
308
309 // ACCESSORS
310
311 /// Return the clock type used for timeouts.
313};
314
315// ============================================================================
316// INLINE DEFINITIONS
317// ============================================================================
318
319 // ------------
320 // class Sluice
321 // ------------
322
323#ifdef BSLS_LIBRARYFEATURES_HAS_CPP11_BASELINE_LIBRARY
324// MANIPULATORS
325template <class CLOCK, class DURATION>
326int Sluice::timedWait(const void *token,
327 const bsl::chrono::time_point<CLOCK, DURATION>& absTime)
328{
329
330 GenerationDescriptor *g =
331 static_cast<GenerationDescriptor *>(const_cast<void *>(token));
332
333 for (;;) {
334 int rc = g->d_sema.timedWait(absTime);
335
336 LockGuard<Mutex> lock(&d_mutex);
337
338 if (g->d_numSignaled) {
339 BSLS_ASSERT(d_pendingGeneration != g);
340
341 --g->d_numSignaled;
342
343 rc = 0;
344 }
345 else if (0 == rc) {
346 continue;
347 }
348
349 const int numThreads = --g->d_numThreads;
350
351 if (0 == numThreads) {
352 // The last thread is responsible for cleanup.
353
354 if (d_signaledGeneration == g) {
355 BSLS_ASSERT(0 != rc);
356 d_signaledGeneration = 0;
357 }
358
359 if (d_pendingGeneration == g) {
360 BSLS_ASSERT(0 != rc);
361 d_pendingGeneration = 0;
362 }
363
364 g->d_next = d_descriptorPool;
365 d_descriptorPool = g;
366 }
367 return rc; // RETURN
368 }
369}
370#endif
371
372// ACCESSORS
373inline
375{
376 return d_clockType;
377}
378
379} // close package namespace
380
381
382#endif
383
384// ----------------------------------------------------------------------------
385// Copyright 2015 Bloomberg Finance L.P.
386//
387// Licensed under the Apache License, Version 2.0 (the "License");
388// you may not use this file except in compliance with the License.
389// You may obtain a copy of the License at
390//
391// http://www.apache.org/licenses/LICENSE-2.0
392//
393// Unless required by applicable law or agreed to in writing, software
394// distributed under the License is distributed on an "AS IS" BASIS,
395// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
396// See the License for the specific language governing permissions and
397// limitations under the License.
398// ----------------------------- END-OF-FILE ----------------------------------
399
400/** @} */
401/** @} */
402/** @} */
Definition bslma_allocator.h:457
Definition bslmt_lockguard.h:234
Definition bslmt_mutex.h:315
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:374
Sluice(const bsl::chrono::steady_clock &, bslma::Allocator *basicAllocator=0)
Sluice(bsls::SystemClockType::Enum clockType, bslma::Allocator *basicAllocator=0)
@ e_TIMED_OUT
Definition bslmt_sluice.h:213
const void * enter()
~Sluice()
Destroy this sluice.
void signalAll()
void signalOne()
Sluice(bslma::Allocator *basicAllocator=0)
Sluice(const bsl::chrono::system_clock &, bslma::Allocator *basicAllocator=0)
Definition bslmt_timedsemaphore.h:221
@ e_TIMED_OUT
Definition bslmt_timedsemaphore.h:234
Definition bsls_timeinterval.h:301
#define BSLS_ASSERT(X)
Definition bsls_assert.h:1804
#define BSLS_IDENT(str)
Definition bsls_ident.h:195
Definition bslmt_barrier.h:344
Enum
Definition bsls_systemclocktype.h:117