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.
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()) ; }
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:
Those are wonderful suggestions Manuel! I put them in the code:
I also don’t need the nextCallTimeMillis_ or yieldMillis_ data members anymore!
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…
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.)
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.
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.
Sad, that is true about wordpress.
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.
🙂
@tr3w. D’oh! As verified by testing, you are correct sir. I’ve reverted back to sleep_for 🙂
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.
Thanks. This is a simple, no frills implementation not intended for heavy duty usage.
Excellent article. Congratulations.
Thanks… Its Really Useful for Debugging process…
You are welcome.
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
Nice Article… Is this applicable for structural oriented proramming language…..