BDE 4.39.x Production Release
Loading...
Searching...
No Matches
bslmt_turnstile.h
Go to the documentation of this file.
1/// @file bslmt_turnstile.h
2///
3/// The content of this file has been pre-processed for Doxygen.
4///
5
6
7// bslmt_turnstile.h -*-C++-*-
8
9#ifndef INCLUDED_BSLMT_TURNSTILE
10#define INCLUDED_BSLMT_TURNSTILE
11
12#include <bsls_ident.h>
13BSLS_IDENT("$Id: $")
14
15/// @defgroup bslmt_turnstile bslmt_turnstile
16/// @brief Provide a mechanism to meter time.
17/// @addtogroup bsl
18/// @{
19/// @addtogroup bslmt
20/// @{
21/// @addtogroup bslmt_turnstile
22/// @{
23///
24/// <h1> Outline </h1>
25/// * <a href="#bslmt_turnstile-purpose"> Purpose</a>
26/// * <a href="#bslmt_turnstile-classes"> Classes </a>
27/// * <a href="#bslmt_turnstile-description"> Description </a>
28/// * <a href="#bslmt_turnstile-comparison-with-sleep"> Comparison with Sleep </a>
29/// * <a href="#bslmt_turnstile-thread-safety"> Thread Safety </a>
30/// * <a href="#bslmt_turnstile-timer-resolution"> Timer Resolution </a>
31/// * <a href="#bslmt_turnstile-usage"> Usage </a>
32/// * <a href="#bslmt_turnstile-example-1-basic-usage"> Example 1: Basic Usage </a>
33///
34/// # Purpose {#bslmt_turnstile-purpose}
35/// Provide a mechanism to meter time.
36///
37/// # Classes {#bslmt_turnstile-classes}
38///
39/// - bslmt::Turnstile: mechanism to meter time
40///
41/// # Description {#bslmt_turnstile-description}
42/// This component provides a mechanism, `bslmt::Turnstile`, to
43/// meter time. A turnstile is configured with a rate that specified how many
44/// "events" per second the turnstile should allow. After the rate is set (via
45/// the constructor or the `reset` method), callers may execute the `waitTurn`
46/// method, which blocks until the next interval arrives. If the turnstile is
47/// not called at or above the configured rate (e.g., due to processing
48/// performed at each interval), the turnstile is said to be "lagging behind."
49/// The amount of lag time is obtained from the `lagTime` method.
50///
51/// ## Comparison with Sleep {#bslmt_turnstile-comparison-with-sleep}
52///
53///
54/// A straightforward implementation of metering is to call some form of sleep
55/// (e.g., `bslmt::ThreadUtil::microSleep`) with a computed rate after each
56/// processing step. However, simply calling "sleep" accumulates errors since
57/// this implementation does not account for the time taken during the
58/// processing step. For example, given two functions that take `rate` (turns
59/// per second) and `duration` (expected execution time in seconds), and execute
60/// `rate * duration` calls to `bsl::sqrt`, calling `waitTurn` on a turnstile or
61/// `bslmt::ThreadUtil::microSleep` with duration `1000000 / rate`,
62/// respectively; the elapsed time for each call results in the following table,
63/// showing that the `bslmt::Turnstile` implementation maintains the correct
64/// rate while the `microSleep` implementation accumulates errors.
65/// @code
66/// Elapsed Time
67/// Rate Duration Turnstile Sleep
68/// ---- -------- --------- -----
69/// 10 1 0.900310 0.940390
70/// 100 1 0.980853 1.609041
71/// 500 1 1.000711 4.989093
72/// 1000 1 1.000103 9.988734
73/// @endcode
74///
75/// ## Thread Safety {#bslmt_turnstile-thread-safety}
76///
77///
78/// Except for the `reset` method, this component is thread-safe and
79/// thread-aware, meaning that multiple threads may safely use their own
80/// instances or a shared instance of a `bslmt::Turnstile` object, provided that
81/// `reset` is not called on a turnstile object while another thread is
82/// accessing or modifying the same object.
83///
84/// ## Timer Resolution {#bslmt_turnstile-timer-resolution}
85///
86///
87/// The `waitTurn` method has a resolution of 10 milliseconds. Therefore,
88/// `bslmt::Turnstile` cannot guarantee that all turns can be taken in each one
89/// second interval if a rate higher than 100 turns per second is specified.
90///
91/// ## Usage {#bslmt_turnstile-usage}
92///
93///
94/// This section illustrates intended use of this component.
95///
96/// ### Example 1: Basic Usage {#bslmt_turnstile-example-1-basic-usage}
97///
98///
99/// The following example illustrates the use of `bslmt::Turnstile` to control
100/// the rate of output being written to a specified output stream. The example
101/// function, `heartbeat`, prints a specified message at a specified rate for a
102/// specified duration. An instance of `bsls::Stopwatch` is used to measure
103/// time against the specified duration.
104/// @code
105/// /// Write the specified `message` to the specified `stream` at the
106/// /// specified `rate` (given in messages per second) for the specified
107/// /// `duration`.
108/// static void heartbeat(bsl::ostream& stream,
109/// const bsl::string& message,
110/// double rate,
111/// double duration)
112/// {
113///
114/// bsls::Stopwatch timer;
115/// timer.start();
116/// bslmt::Turnstile turnstile(rate);
117///
118/// while (true) {
119/// turnstile.waitTurn();
120/// if (timer.elapsedTime() >= duration) {
121/// break;
122/// }
123/// stream << message;
124/// }
125/// }
126/// @endcode
127/// The benefits of using `bslmt::Turnstile` in the above example, as opposed to
128/// simply calling `sleep` in a loop, are twofold. Firstly, `bslmt::Turnstile`
129/// automatically accounts for drift caused by additional processing, so the
130/// loop is allowed to execute immediately if the program fails to execute the
131/// loop at the specified `rate`. Secondly, computing the sleep time and
132/// executing the sleep call, are encapsulated in the turnstile component, which
133/// improves the overall readability of the program.
134/// @}
135/** @} */
136/** @} */
137
138/** @addtogroup bsl
139 * @{
140 */
141/** @addtogroup bslmt
142 * @{
143 */
144/** @addtogroup bslmt_turnstile
145 * @{
146 */
147
148#include <bslscm_version.h>
149
150#include <bsls_atomic.h>
151#include <bsls_timeinterval.h>
152#include <bsls_types.h>
153
154
155namespace bslmt {
156
157 // ===============
158 // class Turnstile
159 // ===============
160
161/// This class provides a mechanism to meter time. Using either the
162/// constructor or the `reset` method, the client specifies `rate`,
163/// indicating the number of events per second that the turnstile will
164/// allow. The client then calls `waitTurn`, which will either sleep until
165/// the next event is to occur, or return immediately if `waitTurn` was
166/// called after the next event is due. If `waitTurn` is not called until
167/// after the next event is due, the turnstile is said to be `lagging`
168/// behind, and calls to `waitTurn` will not sleep until the events have caught up with the schedule.
169///
170/// \note Note that calling `waitTurn` a single time
171/// does not bring a turnstile back on schedule. For example, if a
172/// turnstile's configured frequency is one event per second, and the client
173/// is 10 seconds behind schedule, if `waitTurn` were subsequently called
174/// once per second, the turnstile will remain at 10 seconds behind
175/// schedule. The amount by which events are lagging behind the schedule
176/// can be determined via the `lagTime` method, which returns the positive
177/// number of microseconds by which the turnstile is lagging, or 0 if the
178/// turnstile is not behind schedule.
179///
180/// See @ref bslmt_turnstile
182
183 // DATA
184 bsls::AtomicInt64 d_nextTurn; // absolute time of next turn in
185 // microseconds
186
187 bsls::Types::Int64 d_interval; // interval time in microseconds
188
189 mutable bsls::AtomicInt64 d_timestamp; // time of last call to 'now' in
190 // microseconds
191
192 int d_minTimeToCallSleep;
193 // shortest period of time, in
194 // microseconds, that the
195 // 'waitTurn' function will go to
196 // sleep
197
198 // PRIVATE TYPES
199 typedef bsls::Types::Int64 Int64;
200
201 private:
202 // NOT IMPLEMENTED
203 Turnstile(const Turnstile&);
204 Turnstile& operator=(const Turnstile&);
205
206 public:
207 // CREATORS
208
209 /// Create a turnstile object that admits clients at the specified
210 /// `rate`, expressed as the number of turns per second. Optionally
211 /// specify the (relative) `startTime` of the first turn. If
212 /// `startTime` is not specified, the first turn may be taken
213 /// immediately. Optionally specify `minTimeToCallSleep`, the shortest
214 /// period of time in seconds that the `waitTurn` function will go to sleep.
215 ///
216 /// \pre The behavior is undefined unless `0 < rate`.
217 explicit
218 Turnstile(double rate,
219 const bsls::TimeInterval& startTime = bsls::TimeInterval(0),
220 const bsls::TimeInterval& minTimeToCallSleep =
221 bsls::TimeInterval(1e-4));
222
223 /// Destroy this object.
224 ~Turnstile() = default;
225
226 // MANIPULATORS
227
228 /// Reset the rate of this turnstile to the specified `rate`, expressed
229 /// as the number of turns per second. Optionally specify the
230 /// (relative) `startTime` of the first turn. If `startTime` is not
231 /// specified, the first turn may be taken immediately. Optionally
232 /// specify `minTimeToCallSleep`, the shortest period of time in
233 /// seconds that the `waitTurn` function will go to sleep.
234 ///
235 /// \pre The behavior is undefined unless `0 < rate`.
236 /// \note Note that threads blocked on
237 /// `waitTurn` are not interrupted.
238 void reset(double rate,
239 const bsls::TimeInterval& startTime = bsls::TimeInterval(0),
240 const bsls::TimeInterval& minTimeToCallSleep =
241 bsls::TimeInterval(1e-4));
242
243 /// Sleep until the next turn may be taken or return immediately if the
244 /// optionally specified `sleep` is false, this turnstile is lagging
245 /// behind schedule, or if the calculated sleep duration is less than
246 /// `minTimeToCallSleep`. Return the non-negative number of
247 /// microseconds spent waiting, or if `sleep` is false, the number of
248 /// microseconds the function would have had to wait.
249 bsls::Types::Int64 waitTurn(bool sleep = true);
250
251 // ACCESSORS
252
253 /// Return the positive number of microseconds difference between the
254 /// the current time and the next turn, indicating that the turnstile is
255 /// lagging behind the configured rate. Otherwise, return 0.
257};
258
259} // close package namespace
260
261#endif
262
263// ----------------------------------------------------------------------------
264// Copyright 2015 Bloomberg Finance L.P.
265//
266// Licensed under the Apache License, Version 2.0 (the "License");
267// you may not use this file except in compliance with the License.
268// You may obtain a copy of the License at
269//
270// http://www.apache.org/licenses/LICENSE-2.0
271//
272// Unless required by applicable law or agreed to in writing, software
273// distributed under the License is distributed on an "AS IS" BASIS,
274// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
275// See the License for the specific language governing permissions and
276// limitations under the License.
277// ----------------------------- END-OF-FILE ----------------------------------
278
279/** @} */
280/** @} */
281/** @} */
Definition bslmt_turnstile.h:181
Turnstile(double rate, const bsls::TimeInterval &startTime=bsls::TimeInterval(0), const bsls::TimeInterval &minTimeToCallSleep=bsls::TimeInterval(1e-4))
void reset(double rate, const bsls::TimeInterval &startTime=bsls::TimeInterval(0), const bsls::TimeInterval &minTimeToCallSleep=bsls::TimeInterval(1e-4))
~Turnstile()=default
Destroy this object.
bsls::Types::Int64 lagTime() const
bsls::Types::Int64 waitTurn(bool sleep=true)
Definition bsls_atomic.h:896
Definition bsls_timeinterval.h:307
#define BSLS_IDENT(str)
BSLS_IDENT() - insert string into .comment binary segment (if supported)
Definition bsls_ident.h:238
Definition bslmt_barrier.h:344
long long Int64
Definition bsls_types.h:134