Quick Links:

bal | bbl | bdl | bsl

Namespaces

Component bslmt_turnstile
[Package bslmt]

Provide a mechanism to meter time. More...

Namespaces

namespace  bslmt

Detailed Description

Outline
Purpose:
Provide a mechanism to meter time.
Classes:
bslmt::Turnstile mechanism to meter time
Description:
This component provides a mechanism, bslmt::Turnstile, to meter time. A turnstile is configured with a rate that specified how many "events" per second the turnstile should allow. After the rate is set (via the constructor or the reset method), callers may execute the waitTurn method, which blocks until the next interval arrives. If the turnstile is not called at or above the configured rate (e.g., due to processing performed at each interval), the turnstile is said to be "lagging behind." The amount of lag time is obtained from the lagTime method.
Comparison with Sleep:
A straightforward implementation of metering is to call some form of sleep (e.g., bslmt::ThreadUtil::microSleep) with a computed rate after each processing step. However, simply calling "sleep" accumulates errors since this implementation does not account for the time taken during the processing step. For example, given two functions that take rate (turns per second) and duration (expected execution time in seconds), and execute rate * duration calls to bsl::sqrt, calling waitTurn on a turnstile or bslmt::ThreadUtil::microSleep with duration 1000000 / rate, respectively; the elapsed time for each call results in the following table, showing that the bslmt::Turnstile implementation maintains the correct rate while the microSleep implementation accumulates errors.
                     Elapsed Time
  Rate  Duration  Turnstile     Sleep
  ----  --------  ---------     -----
    10         1   0.900310  0.940390
   100         1   0.980853  1.609041
   500         1   1.000711  4.989093
  1000         1   1.000103  9.988734
Thread Safety:
Except for the reset method, this component is thread-safe and thread-aware, meaning that multiple threads may safely use their own instances or a shared instance of a bslmt::Turnstile object, provided that reset is not called on a turnstile object while another thread is accessing or modifying the same object.
Timer Resolution:
The waitTurn method has a resolution of 10 milliseconds. Therefore, bslmt::Turnstile cannot guarantee that all turns can be taken in each one second interval if a rate higher than 100 turns per second is specified.
Usage:
The following example illustrates the use of bslmt::Turnstile to control the rate of output being written to a specified output stream. The example function, heartbeat, prints a specified message at a specified rate for a specified duration. An instance of bsls::Stopwatch is used to measure time against the specified duration.
  static void heartbeat(bsl::ostream&       stream,
                        const bsl::string&  message,
                        double              rate,
                        double              duration)
  {
      // Write the specified 'message' to the specified 'stream' at the
      // specified 'rate' (given in messages per second) for the specified
      // 'duration'.

      bsls::Stopwatch  timer;
      timer.start();
      bslmt::Turnstile turnstile(rate);

      while (true) {
          turnstile.waitTurn();
          if (timer.elapsedTime() >= duration) {
              break;
          }
          stream << message;
      }
  }
The benefits of using bslmt::Turnstile in the above example, as opposed to simply calling sleep in a loop, are twofold. Firstly, bslmt::Turnstile automatically accounts for drift caused by additional processing, so the loop is allowed to execute immediately if the program fails to execute the loop at the specified rate. Secondly, computing the sleep time and executing the sleep call, are encapsulated in the turnstile component, which improves the overall readability of the program.