BDE 4.14.0 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/// Note that we use an unlikely arbitrary value to permit effectively
142/// asserting a `BslOnce` for correct initialization.
143#define BSLS_BSLONCE_INITIALIZER { { 0xdead } }
144
145
146 // This `struct` provides a simple data type for ensuring a block of code
147 // is executed (only) once. Note that this is defined as a `struct` to
148 // allow constant initialization in a global or static context using
149 // `BSLS_BSLONCE_INITIALIZER`.
150struct BslOnce {
151
152 public:
153 // PUBLIC DATA
154 bsls::AtomicOperations::AtomicTypes::Int d_onceState;
155 // The state of the one-time block of code managed
156 // by this object (must be one of the 'State'
157 // values). This value is public to allow static
158 // initialization (with 'BSLS_BSLONCE_INITIALIZER'),
159 // but should never be directly accessed or
160 // modified.
161
162
163 private:
164 // PRIVATE TYPES
165 enum State {
166 // Note that we select unusual integer values in order to more
167 // effectively test (in appropriate build modes) that 'd_onceState'
168 // was correctly initialized.
169
170 e_NOT_ENTERED = 0xdead,
171 e_IN_PROGRESS,
172 e_DONE
173 };
174
175 // PRIVATE MANIPULATORS
176
177 /// Enter the one-time block of code. Return `true` if the one-time
178 /// block of code has been entered, and `false` if the one-time block of
179 /// code has already been executed. If this function returns `false`
180 /// then the thread of execution in which `enter` returned `true` has
181 /// already called `leave` -- i.e., the one-time block of code is
182 /// guaranteed to have *completed* execution. The behavior is undefined
183 /// unless this object was originally initialized to
184 /// `BSLS_BSLONCE_INITIALIZER`. Note that this private variant of
185 /// `enter` does not perform a test before attempting to acquire the
186 /// spin-lock, and is meant to be implemented out of line (so that the
187 /// expected path of `enter` may be more easily inlined).
188 bool doEnter();
189
190 public:
191 // MANIPULATORS
192
193 /// Enter the one-time block of code. Return `true` if the one-time
194 /// block of code has been entered, and `false` if the one-time block of
195 /// code has already been executed. If this function returns `false`
196 /// then the thread of execution in which `enter` returned `true` has
197 /// already called `leave` -- i.e., the one-time block of code is
198 /// guaranteed to have *completed* execution. The behavior is undefined
199 /// unless this object was originally initialized to
200 /// `BSLS_BSLONCE_INITIALIZER`. Note that a successful `enter` locks a
201 /// spin-lock; it is imperative that `leave` be called quickly.
202 bool enter();
203
204 /// Exit the one-time block of code. The behavior is undefined unless
205 /// the caller had previously called `enter`, and `enter` had returned
206 /// `true`.
207 void leave();
208};
209
210
211 // ==================
212 // class BslOnceGuard
213 // ==================
214
215/// This class provides a guard for managing a `BslOnce` for the purpose of
216/// executing a block of code (only) once.
217///
218/// See @ref bsls_bslonce
220
221 private:
222
223 // DATA
224 BslOnce *d_once; // once gate-keeper
225
226 // NOT IMPLEMENTED
228 BslOnceGuard& operator=(const BslOnceGuard&);
229
230
231 public:
232 // CREATORS
233
234 /// Create a guard to manage a block of code that is executed once.
235 BslOnceGuard();
236
237 /// Destroy this guard, and if `enter` had been called on this object
238 /// without a subsequent call to `leave`, then call `leave` to signal
239 /// the completion of the one-time block of code.
241
242 // MANIPULATORS
243
244 /// Enter the one-time block of code that is managed by the specified
245 /// `once`. Return `true` if the one-time block of code has been
246 /// entered, and `false` if the one-time block of code has already been
247 /// executed. If this function returns `false` then the thread of
248 /// execution in which `enter` returned `true` has already called
249 /// `leave` -- i.e., the one-time block of code is guaranteed to have
250 /// *completed* execution. The behavior is undefined unless `once` was
251 /// originally initialized to `BSLS_BSLONCE_INITIALIZER`. Note that a
252 /// successful `enter` locks a spin-lock; it is imperative that `leave`
253 /// be called quickly.
254 bool enter(BslOnce *once);
255
256 /// Exit the one-time block of code. The behavior is undefined unless
257 /// the caller had previously called `enter`, and `enter` had returned
258 /// `true`.
259 void leave();
260};
261
262
263// ============================================================================
264// INLINE DEFINITIONS
265// ============================================================================
266
267 // -------------
268 // class BslOnce
269 // -------------
270
271
272// MANIPULATORS
273inline
275{
277 return false; // RETURN
278 }
279
280 return doEnter();
281};
282
283inline
290
291
292 // ==================
293 // class BslOnceGuard
294 // ==================
295
296
297// CREATORS
298inline
300: d_once(0)
301{
302}
303
304inline
306{
307 if (d_once) {
308 d_once->leave();
309 }
310}
311
312// MANIPULATORS
313inline
315{
318
319 bool success = once->enter();
320
321 // If the block guarded by 'once' has successfully been entered, set
322 // 'd_once' so that 'leave' will be called when this guard is destroyed.
323
324 if (success) {
325 d_once = once;
326 }
327 return success;
328}
329
330inline
332{
334
335 d_once->leave();
336 d_once = 0;
337
338}
339
340} // close package namespace
341
342
343#endif
344
345// ----------------------------------------------------------------------------
346// Copyright 2014 Bloomberg Finance L.P.
347//
348// Licensed under the Apache License, Version 2.0 (the "License");
349// you may not use this file except in compliance with the License.
350// You may obtain a copy of the License at
351//
352// http://www.apache.org/licenses/LICENSE-2.0
353//
354// Unless required by applicable law or agreed to in writing, software
355// distributed under the License is distributed on an "AS IS" BASIS,
356// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
357// See the License for the specific language governing permissions and
358// limitations under the License.
359// ----------------------------- END-OF-FILE ----------------------------------
360
361/** @} */
362/** @} */
363/** @} */
Definition bsls_bslonce.h:219
void leave()
Definition bsls_bslonce.h:331
~BslOnceGuard()
Definition bsls_bslonce.h:305
bool enter(BslOnce *once)
Definition bsls_bslonce.h:314
BslOnceGuard()
Create a guard to manage a block of code that is executed once.
Definition bsls_bslonce.h:299
#define BSLS_BSLONCE_ASSERT_SAFE(x)
Definition bsls_bslonce.h:126
#define BSLS_IDENT(str)
Definition bsls_ident.h:195
Definition bdlt_iso8601util.h:691
static int getIntAcquire(AtomicTypes::Int const *atomicInt)
Definition bsls_atomicoperations.h:1528
static void setIntRelease(AtomicTypes::Int *atomicInt, int value)
Definition bsls_atomicoperations.h:1558
static int getIntRelaxed(AtomicTypes::Int const *atomicInt)
Definition bsls_atomicoperations.h:1534
Definition bsls_bslonce.h:150
bsls::AtomicOperations::AtomicTypes::Int d_onceState
Definition bsls_bslonce.h:154
bool enter()
Definition bsls_bslonce.h:274
void leave()
Definition bsls_bslonce.h:284