BDE 4.14.0 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
169/// caught up with the schedule. Note that calling `waitTurn` a single time
170/// does not bring a turnstile back on schedule. For example, if a
171/// turnstile's configured frequency is one event per second, and the client
172/// is 10 seconds behind schedule, if `waitTurn` were subsequently called
173/// once per second, the turnstile will remain at 10 seconds behind
174/// schedule. The amount by which events are lagging behind the schedule
175/// can be determined via the `lagTime` method, which returns the positive
176/// number of microseconds by which the turnstile is lagging, or 0 if the
177/// turnstile is not behind schedule.
178///
179/// See @ref bslmt_turnstile
181
182 // DATA
183 bsls::AtomicInt64 d_nextTurn; // absolute time of next turn in
184 // microseconds
185
186 bsls::Types::Int64 d_interval; // interval time in microseconds
187
188 mutable bsls::AtomicInt64 d_timestamp; // time of last call to 'now' in
189 // microseconds
190
191 int d_minTimeToCallSleep;
192 // shortest period of time, in
193 // microseconds, that the
194 // 'waitTurn' function will go to
195 // sleep
196
197 // PRIVATE TYPES
198 typedef bsls::Types::Int64 Int64;
199
200 private:
201 // NOT IMPLEMENTED
202 Turnstile(const Turnstile&);
203 Turnstile& operator=(const Turnstile&);
204
205 public:
206 // CREATORS
207
208 /// Create a turnstile object that admits clients at the specified
209 /// `rate`, expressed as the number of turns per second. Optionally
210 /// specify the (relative) `startTime` of the first turn. If
211 /// `startTime` is not specified, the first turn may be taken
212 /// immediately. Optionally specify `minTimeToCallSleep`, the shortest
213 /// period of time in seconds that the `waitTurn` function will go to
214 /// sleep. The behavior is undefined unless `0 < rate`.
215 explicit
216 Turnstile(double rate,
217 const bsls::TimeInterval& startTime = bsls::TimeInterval(0),
218 const bsls::TimeInterval& minTimeToCallSleep =
219 bsls::TimeInterval(1e-4));
220
221 /// Destroy this object.
222 ~Turnstile() = default;
223
224 // MANIPULATORS
225
226 /// Reset the rate of this turnstile to the specified `rate`, expressed
227 /// as the number of turns per second. Optionally specify the
228 /// (relative) `startTime` of the first turn. If `startTime` is not
229 /// specified, the first turn may be taken immediately. Optionally
230 /// specify `minTimeToCallSleep`, the shortest period of time in
231 /// seconds that the `waitTurn` function will go to sleep. The behavior
232 /// is undefined unless `0 < rate`. Note that threads blocked on
233 /// `waitTurn` are not interrupted.
234 void reset(double rate,
235 const bsls::TimeInterval& startTime = bsls::TimeInterval(0),
236 const bsls::TimeInterval& minTimeToCallSleep =
237 bsls::TimeInterval(1e-4));
238
239 /// Sleep until the next turn may be taken or return immediately if the
240 /// optionally specified `sleep` is false, this turnstile is lagging
241 /// behind schedule, or if the calculated sleep duration is less than
242 /// `minTimeToCallSleep`. Return the non-negative number of
243 /// microseconds spent waiting, or if `sleep` is false, the number of
244 /// microseconds the function would have had to wait.
245 bsls::Types::Int64 waitTurn(bool sleep = true);
246
247 // ACCESSORS
248
249 /// Return the positive number of microseconds difference between the
250 /// the current time and the next turn, indicating that the turnstile is
251 /// lagging behind the configured rate. Otherwise, return 0.
253};
254
255} // close package namespace
256
257#endif
258
259// ----------------------------------------------------------------------------
260// Copyright 2015 Bloomberg Finance L.P.
261//
262// Licensed under the Apache License, Version 2.0 (the "License");
263// you may not use this file except in compliance with the License.
264// You may obtain a copy of the License at
265//
266// http://www.apache.org/licenses/LICENSE-2.0
267//
268// Unless required by applicable law or agreed to in writing, software
269// distributed under the License is distributed on an "AS IS" BASIS,
270// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
271// See the License for the specific language governing permissions and
272// limitations under the License.
273// ----------------------------- END-OF-FILE ----------------------------------
274
275/** @} */
276/** @} */
277/** @} */
Definition bslmt_turnstile.h:180
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:892
Definition bsls_timeinterval.h:301
#define BSLS_IDENT(str)
Definition bsls_ident.h:195
Definition bslmt_barrier.h:344
long long Int64
Definition bsls_types.h:132