Home > C++11 > PeriodicFunction

PeriodicFunction

In the embedded systems application domain, there is often the need to execute one or more background functions at a periodic rate. Before C++11 rolled onto the scene, a programmer had to use a third party library like ACE/Boost/Poco/Qt to incorporate that functionality into the product. However, with the inclusion of std::thread, std::bind, and std::chrono in C++11, there is no longer the need to include those well-crafted libraries into the code base to achieve that specific functionality.

Periodic Function Execution

The following figure shows the interface of a class template that I wrote to provide users with the capability to execute a function object (of type std::function<void()>) at a periodic rate over a fixed length of time.

Periodic Function Iface

Upon instantiation of a PeriodicFunction object, the class executes the Functor immediately and then re-executes it every periodMillis until expiration at durationMillis. The hasExpired(), stop(), and restart() functions provide users with convenient query/control options after construction.

The figure below depicts the usage of the PeriodicFunction class. In the top block of code, a lambda function is created and placed into execution every 200 milliseconds over a 1 second duration. After waiting for those 5 executions to complete, the code restarts the PeriodicFunction to run the lambda every 500 milliseconds for 1.5 seconds. The last code segment defines a Functor class, creates an object instance of it, and places the functor into execution at 50 millisecond intervals over a duration of 250 milliseconds.

Periodic Function Usage

The output of a single run of the program is shown below. Note that the actual output matches what is expected: 5 executions spaced at 200 millisecond intervals; 3 executions spaced at 500millisecond intervals; and 5 executions spaced at 50 millisecond intervals.

Periodic Function Output

In case you want to use, experiment with, or enhance the code, the implementation of the PeriodicFunction class template is provided in copy & paste form as follows:


#ifndef PERIODICFUNCTION_H_
#define PERIODICFUNCTION_H_

#include <cstdint>
#include <thread>
#include <mutex>
#include <chrono>
#include <atomic>

namespace pf {

using std::chrono::steady_clock;
using std::chrono::duration;
using std::chrono::milliseconds;

template<typename Functor>
class PeriodicFunction {
public:
  //Initialize the timer state and start the timing loop
  PeriodicFunction(uint32_t periodMillis, uint32_t durationMillis,
      Functor& callback, int32_t yieldMillis = DEFAULT_YIELD_MILLIS) :
      func_(callback),
      periodMillis_(periodMillis),
      expirationTime_(steady_clock::now()
              + steady_clock::duration(milliseconds(durationMillis))),
      nextCallTimeMillis_(steady_clock::now()), yieldMillis_(yieldMillis) {
    //Start the timing loop
    t_ = std::thread { PeriodicFunction::threadLoop, this };
  }

  //Command & wait for the threadLoop to stop
  //before this object gets de-constructed
  ~PeriodicFunction() {
    stop();
  }

  bool hasExpired() const {
    return hasExpired_;
  }

  void stop() {
    isRunning_ = false;
    if (t_.joinable())
      t_.join();
  }

  void restart(uint32_t periodMillis, uint32_t durationMillis) {
    std::lock_guard<std::mutex> lg(stateMutex_);
    //Stop the current timer if needed
    stop();

    //What time is it right at this instant?
    auto now = steady_clock::now();

    //Set the state for the new timer
    expirationTime_ = now + milliseconds(durationMillis);
    nextCallTimeMillis_ = now;
    periodMillis_ = periodMillis;
    hasExpired_ = false;

    //Start the timing loop
    isRunning_ = true;
    t_ = std::thread { PeriodicFunction::threadLoop, this };
  }

  //Since we retain a reference to a Functor object, prevent copying
  //and moving
  PeriodicFunction(const PeriodicFunction& rhs) = delete;
  PeriodicFunction& operator=(const PeriodicFunction& rhs) = delete;
  PeriodicFunction(PeriodicFunction&& rhs) = delete;
  PeriodicFunction& operator=(PeriodicFunction&& rhs) = delete;

private:
  //The function to be executed periodically until we're done
  Functor& func_;

  //The period at which the function is executed
  uint32_t periodMillis_;

  //The absolute time at which we declare "done done!"
  steady_clock::time_point expirationTime_;

  //The next scheduled function execution time
  steady_clock::time_point nextCallTimeMillis_;

  //The thread sleep duration; the larger the value,
  //the more we decrease the periodic execution accuracy;
  //allows other sibling threads threads to use the cpu
  uint32_t yieldMillis_;

  //The default sleep duration of each pass thru
  //the timing loop
  static constexpr uint32_t DEFAULT_YIELD_MILLIS { 10 };

  //Indicates whether the timer has expired or not
  std::atomic<bool> hasExpired_ { false };

  //Indicates whether the monitoring loop is active
  //probably doesn't need to be atomic, but good practice
  std::atomic<bool> isRunning_ { true };

  //Our precious thread resource!
  std::thread t_ { };

  //Protects the timer state from data races
  //between our private thread and the caller's thread
  std::mutex stateMutex_ { };

  //The timing loop
  void threadLoop() {
    while (isRunning_) {
      auto now = steady_clock::now();//What time is it right at this instant?
      std::lock_guard<std::mutex> lg(stateMutex_);
      if (now >= expirationTime_) { //Has the timer expired?
        hasExpired_ = true;
        return;
      }
      else if (now > nextCallTimeMillis_) {//Time to execute function?
        nextCallTimeMillis_ = now + milliseconds(periodMillis_);
        std::bind(&Functor::operator(), std::ref(func_))(); //Execute!
        continue; //Skip the sleep
      }
      //Unselfish sharing; let other threads have the cpu for a bit
      std::this_thread::sleep_for(milliseconds(yieldMillis_));
    }
  }
};
//End of the class definition
}//namespace pf

#endif /* PERIODICFUNCTION_H_ */

One potential improvement that comes to mind is the addition of the capability to periodically execute the user-supplied functor literally “forever” – and not cheating by setting durationMillis to 0xFFFFFFFF (which is not forever). Another improvement might be to support variadic template args (like the std::thread ctor does) to allow any function type to be placed into execution – not just those of type  std::function<void()>.

In case you don’t want to type in the test driver code, here it is in copy & paste form:


#include <iostream>
#include <chrono>
#include "PeriodicFunction.h"

int main() {
  //Create a lambda and plcae into execution
  //every 200 millis over a duration of 1 second
  using namespace std::chrono;
  steady_clock::time_point startTime { steady_clock::now() };
  steady_clock::time_point execTime { startTime };
  auto lambda = [&] { //We don't need the ()
    using namespace std::chrono;
    execTime = steady_clock::now();
    std::cout << "lambda executed at T="
              << duration_cast<milliseconds>(execTime - startTime).count()
              << std::endl;
    startTime = execTime;
  };
  pf::PeriodicFunction<decltype(lambda)> pf1 { 200, 1000, lambda };
  while (!pf1.hasExpired()) ;
  std::cout << std::endl;

  //Re-run the lambda every half second for a second
  startTime = steady_clock::now();
  execTime = startTime;
  pf1.restart(500, 1500);
  while (!pf1.hasExpired()) ;
  std::cout << std::endl;

  //Define a stateful Functor class
  class Functor {
  public:
    Functor() :
        startTime_ { steady_clock::now() }, execTime_ { startTime_ } {
    }
    void operator()() {
      execTime_ = steady_clock::now();
      std::cout << "Functor::operator() executed at T="
          << duration_cast<milliseconds>(execTime_ - startTime_).count()
          << std::endl;
      startTime_ = execTime_;
    }
  private:
    steady_clock::time_point startTime_;
    steady_clock::time_point execTime_;
  };

  //Create a Functor object and place into execution
  //every 50 millis over a duration of 250 millis
  Functor myFunction { };
  pf::PeriodicFunction<Functor> pf2 { 50, 250, myFunction, 0 };
  while (!pf2.hasExpired()) ;
}

Categories: C++11 Tags:
  1. Manuel
    July 15, 2015 at 3:52 am

    Nice solution. I would just make the following suggestions:

    Use std::this_thread::sleep_until(). You can specify when you would like to wake up. This avoids sleeping for short durations and the manual book keeping.
    Do not block stateMutex_ while sleeping.
    Store periodMillis_ and yieldMillis_ directly in chrono::millisecondsvaribles instead of
    using uint32_t. IMHO this makes the code more readable because uint32_t can be just anything but crono::milliseconds is a duration.

    Probably the basic loop can be written like this:

    auto timePoint = chrono::steady_clock::now();
    while (isRunning_)
    {
        std::unique_lock<std::mutex> guard(stateMutex_);
        // Handle expiration.
        guard.unlock();
    
        // Call user function. Probably keep the mutex locked here.
    
        timePoint += periodMillis_;
        std::this_thread::sleep_until(timePoint);
    }
    
    • July 15, 2015 at 4:31 am

      Those are wonderful suggestions Manuel! I put them in the code:

      
        //The timing loop
        void threadLoop() {
          while (isRunning_) {
            auto now = steady_clock::now();//What time is it right at this instant?
            std::unique_lock lg(stateMutex_);
            if (now >= expirationTime_) { //Has the timer expired?
              hasExpired_ = true;
              return;
            }
            std::bind(&Functor::operator(), std::ref(func_))(); //Execute!
            lg.unlock();
            std::this_thread::sleep_until(now + milliseconds(periodMillis_));
          }
        }
      
      

      I also don’t need the nextCallTimeMillis_ or yieldMillis_ data members anymore!

      • tr3w
        July 15, 2015 at 4:50 am

        The only problem with this solution is that you can not stop (and destroy) your PeriodicFunction earlier than the next run, which can be annoying if the period is 5 minutes. 🙂

        Maybe you can use a condition variable with wait_until or a timed_mutex with try_lock_until…

  2. July 15, 2015 at 3:56 am

    I’ve had similar problem to solve. Instead of pooling the timers every yieldMillis I’ve come up with a solution using timed_mutex::try_lock_for: https://github.com/etam/fortuna/blob/master/src/libfortuna/repeating_task.hpp https://github.com/etam/fortuna/blob/master/src/libfortuna/repeating_task.cpp . This allows the thread to sleep specified amount of time and to be canceled at any moment. (There is a potential problem with spurious wake-ups, but I couldn’t find a way to evoke them.)

  3. Mario Lang
    July 15, 2015 at 3:59 am

    Apparently, all your source code examples are presented as images. This is very bad for accessibility, in particular for blind people (like me) who want to read your articles. If you find the time and motivation, it would be very nice if you could find a way for your source examples to be presented as normal text, like on 99% of all the other code related blogs I know.

    • July 15, 2015 at 4:04 am

      Sorry about that Mario. I never thought I’d get so many hits on my C++ posts. I don’t think I have the time to go back over the whole set of my previous C++ posts to do as you ask, but I will do it going forward. This post has both the .png version and text versions. I find the syntax highlighting/coloring in IDEs like Eclipse much better than the wordpress renderings. Plus, wordpress has the annoying habit of randomly replacing constructs like “>>” with text escape codes. A pain in my butt.

      • July 15, 2015 at 7:56 am

        Sad, that is true about wordpress.

      • July 15, 2015 at 2:46 pm

        Man do I ever sympathize. I started a c++ blog recently as well, the random swallowing of angle braces is brutal. I do also prefer Eclipse’s syntax highlighting, but I can live with that.

      • July 15, 2015 at 2:48 pm

        🙂

  4. July 15, 2015 at 5:07 am

    @tr3w. D’oh! As verified by testing, you are correct sir. I’ve reverted back to sleep_for 🙂

  5. July 15, 2015 at 9:25 am

    Supporting a lot of timers is not an easy task. There are several approaches like timer_wheel, timer_heap, timer_list. Each approach has its own benefits and drawbacks.
    I have implemented three main approaches in lightweight header-only library timertt: https://sourceforge.net/p/sobjectizer/wiki/timertt%201.1/ It is based on C++11 only and can handle millions and even billions of timers.

    BTW, one of the most feature rich implementation of various types of timers is in ACE framework.

    • July 15, 2015 at 9:51 am

      Thanks. This is a simple, no frills implementation not intended for heavy duty usage.

  6. Carlos Eduardo Olivieri
    July 15, 2015 at 8:17 pm

    Excellent article. Congratulations.

  7. July 16, 2015 at 7:37 am

    Thanks… Its Really Useful for Debugging process…

  8. Sandeep Kalra
    July 16, 2015 at 11:27 am

    Nice Solution.

    I am relatively new to C++11 but I implemented a very similar function to cater to my needs with (C-ish C++11). Good to see full C++11 imp.

    A modified version of my code is at:
    https://github.com/sandeepkalra/utilities/blob/e718a7240c54166fe581ea280e96dc4c33b0c5b5/timer.cpp

  9. July 21, 2015 at 8:03 am

    Nice Article… Is this applicable for structural oriented proramming language…..

  1. No trackbacks yet.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

This site uses Akismet to reduce spam. Learn how your comment data is processed.

%d bloggers like this: