Search code examples
c#c++c++-chrono

periodic timer intervals in C++


I'm converting a code from C# to C++. I want to call a function every at periodic time intervals. My original function in C# is:

private void Init_timerGetData()
{
    timerGetData = new Timer();
    timerGetData.Interval = 5;
    timerGetData.Tick += new EventHandler(ReadData_Tick);
}

private void ReadData_Tick(object sender, EventArgs e)
   {...}

How to re-write this function in C++ in order to get the same functionality?


Solution

  • You can roll your own with a class that launches a thread to do the calls. Here's a simple one I use that will call every period until the class's destructor runs. You can tweak the details of the implementation to achieve most anything you want:

    #include <atomic>
    #include <chrono>
    #include <functional>
    #include <thread>
    
    class call_every
    {
        std::function<void()> f_;
        std::chrono::system_clock::duration d_;
        std::chrono::system_clock::time_point run_now_;
        std::atomic_bool quit_;
        std::thread thr_;
    
    public:
        ~call_every()
        {
            quit_ = true;
            thr_.join();
        }
    
        template <class F>
        explicit call_every(F f, std::chrono::system_clock::duration d)
            : f_{std::move(f)}
            , d_{d}
            , run_now_{std::chrono::system_clock::now()}
            , quit_{false}
            , thr_{&call_every::run, this}
            {}
    
    private:
        void run()
        {
            while (!quit_)
            {
                f_();
                run_now_ += d_;
                std::this_thread::sleep_until(run_now_);
            }
        }
    };
    
    #include <iostream>
    
    int
    main()
    {
        using namespace std;
        using namespace std::chrono;
        call_every x{[]{cout << "Hi" << endl;}, 5s};
        this_thread::sleep_for(15s);
    }
    
    $ a.out
    Hi
    Hi
    Hi
    Hi
    $
    

    Here's a variant of the above that will be more responsive to the quit_ command. Instead of unconditionally sleeping for the duration, it uses a condition_variable with a wait_until which ~call_every() can interrupt before the duration times out. This ensures a more timely shutdown, should that be important.

    #include <chrono>
    #include <condition_variable>
    #include <functional>
    #include <mutex>
    #include <thread>
    
    class call_every
    {
        std::mutex mut_;
        std::condition_variable cv_;
        std::function<void()> f_;
        std::chrono::system_clock::duration d_;
        std::chrono::system_clock::time_point run_now_;
        bool quit_;
        std::thread thr_;
    
    public:
        ~call_every()
        {
            {
                std::lock_guard lock{mut_};
                quit_ = true;
            }
            cv_.notify_one();
            thr_.join();
        }
    
        template <class F>
        explicit call_every(F f, std::chrono::system_clock::duration d)
            : f_{std::move(f)}
            , d_{d}
            , run_now_{std::chrono::system_clock::now()}
            , quit_{false}
            , thr_{&call_every::run, this}
            {
            }
    
    private:
        void run()
        {
            while (true)
            {
                f_();
                run_now_ += d_;
                std::unique_lock lock{mut_};
                if (cv_.wait_until(lock, run_now_, [this]() {return quit_;}))
                    break;
            }
        }
    };