BDE 4.39.x Production Release
Loading...
Searching...
No Matches
bsls_bslonce.h
Go to the documentation of this file.
1/// @file bsls_bslonce.h
2///
3/// The content of this file has been pre-processed for Doxygen.
4///
5
6
7// bsls_bslonce.h -*-C++-*-
8#ifndef INCLUDED_BSLS_BSLONCE
9#define INCLUDED_BSLS_BSLONCE
10
11#include <bsls_ident.h>
12BSLS_IDENT("$Id: $")
13
14/// @defgroup bsls_bslonce bsls_bslonce
15/// @brief Provide BSL a thread-safe way to execute code once per process.
16/// @addtogroup bsl
17/// @{
18/// @addtogroup bsls
19/// @{
20/// @addtogroup bsls_bslonce
21/// @{
22///
23/// <h1> Outline </h1>
24/// * <a href="#bsls_bslonce-purpose"> Purpose</a>
25/// * <a href="#bsls_bslonce-classes"> Classes </a>
26/// * <a href="#bsls_bslonce-description"> Description </a>
27/// * <a href="#bsls_bslonce-usage"> Usage </a>
28/// * <a href="#bsls_bslonce-example-1-using-bsls-bslonce-to-perform-a-singleton-initialization"> Example 1: Using bsls::BslOnce to Perform a Singleton Initialization </a>
29///
30/// # Purpose {#bsls_bslonce-purpose}
31/// Provide BSL a thread-safe way to execute code once per process.
32///
33/// # Classes {#bsls_bslonce-classes}
34///
35/// - bsls::BslOnce: statically initializable gate-keeper for a once-block
36/// - bsls::BslOnceGuard: guard for safely using `bsls::BslOnce`
37///
38/// # Description {#bsls_bslonce-description}
39/// This component provides a pair of classes, `bsls::BslOnce`
40/// and `bsls::BslOnceGuard`, which give the caller a way to run a block of
41/// code exactly once within the current process, particularly in the presence
42/// of multiple threads. The typical purpose of this one-time execution is the
43/// initialization of a singleton on first use.
44///
45/// [**WARNING**] Clients outside of `bsl` should *not* use this component.
46/// Because of its location in the hierarchy, this component guards critical
47/// sections using a spin-lock. Equivalent components that are more robust and
48/// efficient will be provided at a higher level (see @ref bslmt_once ).
49///
50/// A `bsls::BslOnce` object can be statically initialized using the
51/// `BSLS_BSLONCE_INITIALIZER` macro.
52///
53/// ## Usage {#bsls_bslonce-usage}
54///
55///
56/// This section illustrates intended use of this component.
57///
58/// ### Example 1: Using bsls::BslOnce to Perform a Singleton Initialization {#bsls_bslonce-example-1-using-bsls-bslonce-to-perform-a-singleton-initialization}
59///
60///
61/// The following example demonstrates using `bsls::BslOnce` to initialize a
62/// singleton object.
63///
64/// First we declare a `struct`, `MySingleton`, whose definition is elided:
65/// @code
66/// struct MySingleton {
67///
68/// // PUBLIC DATA
69/// int d_exampleData;
70///
71/// // ...
72/// };
73/// @endcode
74/// Notice that the data members are public because we want to avoid dynamic
75/// runtime initialize (i.e., initialization at run-time before the start of
76/// `main`) when an object of this type is declared in a static context.
77///
78/// Now we implement a function `getSingleton` that returns a singleton object.
79/// `getSingleton` uses `BslOnce` to ensure the singleton is initialized only
80/// once, and that the singleton is initialized before the function returns:
81/// @code
82/// /// Return a reference to a modifiable singleton object.
83/// MySingleton *getSingleton()
84/// {
85/// static MySingleton singleton = { 0 };
86/// static BslOnce once = BSLS_BSLONCE_INITIALIZER;
87///
88/// BslOnceGuard onceGuard;
89/// if (onceGuard.enter(&once)) {
90/// // Initialize 'singleton'. Note that this code is executed exactly
91/// // once.
92///
93/// }
94/// return &singleton;
95/// }
96/// @endcode
97/// Notice that `BslOnce` must be initialized to `BSLS_BSLONCE_INITIALIZER`, and
98/// that `singleton` is a function scoped static variable to avoid allocating
99/// it on the `heap` (which might be reported as leaked memory).
100/// @}
101/** @} */
102/** @} */
103
104/** @addtogroup bsl
105 * @{
106 */
107/** @addtogroup bsls
108 * @{
109 */
110/** @addtogroup bsls_bslonce
111 * @{
112 */
113
114#include <bsls_atomicoperations.h>
115
116#ifdef BDE_BUILD_TARGET_SAFE
117// This component needs to be below bsls_assert in the physical hierarchy, so
118// 'BSLS_ASSERT' macros can't be used here. To workaround this issue, we use
119// the C 'assert' instead.
120
121#include <assert.h>
122#define BSLS_BSLONCE_ASSERT_SAFE(x) assert((x))
123
124#else
125
126#define BSLS_BSLONCE_ASSERT_SAFE(x)
127
128#endif
129
130
131namespace bsls {
132
133 // =============
134 // class BslOnce
135 // =============
136
137/// Use this macro to initialize an object of type `bsls::Once`. E.g.:
138/// @code
139/// bsls::Once once = BSLS_BSLONCE_INITIALIZER;
140/// @endcode
141///
142/// \note Note that we use an unlikely arbitrary value to permit effectively
143/// asserting a `BslOnce` for correct initialization.
144#define BSLS_BSLONCE_INITIALIZER { { 0xdead } }
145
146
147 // This `struct` provides a simple data type for ensuring a block of code
148 // is executed (only) once. Note that this is defined as a `struct` to
149 // allow constant initialization in a global or static context using
150 // `BSLS_BSLONCE_INITIALIZER`.
151struct BslOnce {
152
153 public:
154 // PUBLIC DATA
155 bsls::AtomicOperations::AtomicTypes::Int d_onceState;
156 // The state of the one-time block of code managed
157 // by this object (must be one of the 'State'
158 // values). This value is public to allow static
159 // initialization (with 'BSLS_BSLONCE_INITIALIZER'),
160 // but should never be directly accessed or
161 // modified.
162
163
164 private:
165 // PRIVATE TYPES
166 enum State {
167 // Note that we select unusual integer values in order to more
168 // effectively test (in appropriate build modes) that 'd_onceState'
169 // was correctly initialized.
170
171 e_NOT_ENTERED = 0xdead,
172 e_IN_PROGRESS,
173 e_DONE
174 };
175
176 // PRIVATE MANIPULATORS
177
178 /// Enter the one-time block of code. Return `true` if the one-time
179 /// block of code has been entered, and `false` if the one-time block of
180 /// code has already been executed. If this function returns `false`
181 /// then the thread of execution in which `enter` returned `true` has
182 /// already called `leave` -- i.e., the one-time block of code is
183 /// guaranteed to have *completed* execution.
184 ///
185 /// \pre The behavior is undefined unless this object was originally initialized to `BSLS_BSLONCE_INITIALIZER`.
186 ///
187 /// \note Note that this private variant of
188 /// `enter` does not perform a test before attempting to acquire the
189 /// spin-lock, and is meant to be implemented out of line (so that the
190 /// expected path of `enter` may be more easily inlined).
191 bool doEnter();
192
193 public:
194 // MANIPULATORS
195
196 /// Enter the one-time block of code. Return `true` if the one-time
197 /// block of code has been entered, and `false` if the one-time block of
198 /// code has already been executed. If this function returns `false`
199 /// then the thread of execution in which `enter` returned `true` has
200 /// already called `leave` -- i.e., the one-time block of code is
201 /// guaranteed to have *completed* execution.
202 ///
203 /// \pre The behavior is undefined unless this object was originally initialized to `BSLS_BSLONCE_INITIALIZER`.
204 ///
205 /// \note Note that a successful `enter` locks a
206 /// spin-lock; it is imperative that `leave` be called quickly.
207 bool enter();
208
209 /// Exit the one-time block of code.
210 /// \pre The behavior is undefined unless
211 /// the caller had previously called `enter`, and `enter` had returned
212 /// `true`.
213 void leave();
214};
215
216
217 // ==================
218 // class BslOnceGuard
219 // ==================
220
221/// This class provides a guard for managing a `BslOnce` for the purpose of
222/// executing a block of code (only) once.
223///
224/// See @ref bsls_bslonce
226
227 private:
228
229 // DATA
230 BslOnce *d_once; // once gate-keeper
231
232 private:
233 // NOT IMPLEMENTED
235 BslOnceGuard& operator=(const BslOnceGuard&);
236
237
238 public:
239 // CREATORS
240
241 /// Create a guard to manage a block of code that is executed once.
242 BslOnceGuard();
243
244 /// Destroy this guard, and if `enter` had been called on this object
245 /// without a subsequent call to `leave`, then call `leave` to signal
246 /// the completion of the one-time block of code.
248
249 // MANIPULATORS
250
251 /// Enter the one-time block of code that is managed by the specified
252 /// `once`. Return `true` if the one-time block of code has been
253 /// entered, and `false` if the one-time block of code has already been
254 /// executed. If this function returns `false` then the thread of
255 /// execution in which `enter` returned `true` has already called
256 /// `leave` -- i.e., the one-time block of code is guaranteed to have *completed* execution.
257 ///
258 /// \pre The behavior is undefined unless `once` was originally initialized to `BSLS_BSLONCE_INITIALIZER`.
259 ///
260 /// \note Note that a
261 /// successful `enter` locks a spin-lock; it is imperative that `leave`
262 /// be called quickly.
263 bool enter(BslOnce *once);
264
265 /// Exit the one-time block of code.
266 /// \pre The behavior is undefined unless
267 /// the caller had previously called `enter`, and `enter` had returned
268 /// `true`.
269 void leave();
270};
271
272
273// ============================================================================
274// INLINE DEFINITIONS
275// ============================================================================
276
277 // -------------
278 // class BslOnce
279 // -------------
280
281
282// MANIPULATORS
283inline
285{
287 return false; // RETURN
288 }
289
290 return doEnter();
291};
292
293inline
300
301
302 // ==================
303 // class BslOnceGuard
304 // ==================
305
306
307// CREATORS
308inline
310: d_once(0)
311{
312}
313
314inline
316{
317 if (d_once) {
318 d_once->leave();
319 }
320}
321
322// MANIPULATORS
323inline
325{
328
329 bool success = once->enter();
330
331 // If the block guarded by 'once' has successfully been entered, set
332 // 'd_once' so that 'leave' will be called when this guard is destroyed.
333
334 if (success) {
335 d_once = once;
336 }
337 return success;
338}
339
340inline
342{
344
345 d_once->leave();
346 d_once = 0;
347
348}
349
350} // close package namespace
351
352
353#endif
354
355// ----------------------------------------------------------------------------
356// Copyright 2014 Bloomberg Finance L.P.
357//
358// Licensed under the Apache License, Version 2.0 (the "License");
359// you may not use this file except in compliance with the License.
360// You may obtain a copy of the License at
361//
362// http://www.apache.org/licenses/LICENSE-2.0
363//
364// Unless required by applicable law or agreed to in writing, software
365// distributed under the License is distributed on an "AS IS" BASIS,
366// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
367// See the License for the specific language governing permissions and
368// limitations under the License.
369// ----------------------------- END-OF-FILE ----------------------------------
370
371/** @} */
372/** @} */
373/** @} */
Definition bsls_bslonce.h:225
void leave()
Definition bsls_bslonce.h:341
~BslOnceGuard()
Definition bsls_bslonce.h:315
bool enter(BslOnce *once)
Definition bsls_bslonce.h:324
BslOnceGuard()
Create a guard to manage a block of code that is executed once.
Definition bsls_bslonce.h:309
#define BSLS_BSLONCE_ASSERT_SAFE(x)
Definition bsls_bslonce.h:126
#define BSLS_IDENT(str)
BSLS_IDENT() - insert string into .comment binary segment (if supported)
Definition bsls_ident.h:238
Definition bdlt_iso8601util.h:707
static int getIntAcquire(AtomicTypes::Int const *atomicInt)
Definition bsls_atomicoperations.h:1530
static void setIntRelease(AtomicTypes::Int *atomicInt, int value)
Definition bsls_atomicoperations.h:1560
static int getIntRelaxed(AtomicTypes::Int const *atomicInt)
Definition bsls_atomicoperations.h:1536
Definition bsls_bslonce.h:151
bsls::AtomicOperations::AtomicTypes::Int d_onceState
Definition bsls_bslonce.h:155
bool enter()
Definition bsls_bslonce.h:284
void leave()
Definition bsls_bslonce.h:294