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.

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.

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.

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.

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()) ; }