need to call a function at periodic time intervals

2019-01-09 07:25发布

I am writing a program in c++ where I need to call a function at periodic time intervals, say every 10ms or so. I've never done anything related to time or clocks in c++, is this a quick and easy problem or one of those where there is no neat solution?

Thanks!

6条回答
爱情/是我丢掉的垃圾
2楼-- · 2019-01-09 07:57

A simple timer can be implemented as follows,

#include <iostream>
#include <chrono>
#include <thread>
#include <functional>

void timer_start(std::function<void(void)> func, unsigned int interval)
{
    std::thread([func, interval]() {
        while (true)
        {
            func();
            std::this_thread::sleep_for(std::chrono::milliseconds(interval));
        }
    }).detach();
}


void do_something()
{
    std::cout << "I am doing something" << std::endl;
}

int main() {
    timer_start(do_something, 1000);

    while(true);
}

This simple solution does not offer a way to stop the timer. The timer will keep running until the program exited.

查看更多
该账号已被封号
3楼-- · 2019-01-09 08:00

Sorry, but I didn't find a design simpler than that.

You could, make a class that owns both a thread, and a weak_ptr to itself, to be a "holder" that the callable can see it safely, because the callable will still exists even if the object is destructed. You don't want a dangling pointer.

template<typename T>
struct IntervalRepeater {
    using CallableCopyable = T;
private:
    weak_ptr<IntervalRepeater<CallableCopyable>> holder;
    std::thread theThread;

    IntervalRepeater(unsigned int interval,
            CallableCopyable callable): callable(callable), interval(interval) {}

    void thread() {
        weak_ptr<IntervalRepeater<CallableCopyable>> holder = this->holder;
        theThread = std::thread([holder](){
            // Try to strongify the pointer, to make it survive this loop iteration,
            //    and ensure that this pointer is valid, if not valid, end the loop.
            while (shared_ptr<IntervalRepeater<CallableCopyable>> ptr = holder.lock()) {
                auto x = chrono::steady_clock::now() + chrono::milliseconds(ptr->interval);
                ptr->callable();
                this_thread::sleep_until(x);
            }
        });
    }

public:
    const CallableCopyable callable;
    const unsigned int interval;

    static shared_ptr<IntervalRepeater<T>> createIntervalRepeater(unsigned int interval,
            CallableCopyable callable) {
        std::shared_ptr<IntervalRepeater<CallableCopyable>> ret =
                shared_ptr<IntervalRepeater<CallableCopyable>>(
                        new IntervalRepeater<CallableCopyable>(interval, callable));
        ret->holder = ret;
        ret->thread();

        return ret;
    }

    ~IntervalRepeater() {
        // Detach the thread before it is released.
        theThread.detach();
    }

};

void beginItWaitThenDestruct() {
    auto repeater = IntervalRepeater<function<void()>>::createIntervalRepeater(
            1000, [](){ cout << "A second\n"; });
    std::this_thread::sleep_for(std::chrono::milliseconds(3700));
}

int main() {
    beginItWaitThenDestruct();
    // Wait for another 2.5 seconds, to test whether there is still an effect of the object
    //   or no.
    std::this_thread::sleep_for(std::chrono::milliseconds(2500));
    return 0;
}
查看更多
Bombasti
4楼-- · 2019-01-09 08:01

To complete the question, the code from @user534498 can be easily adapted to have the periodic tick interval. It's just needed to determinate the next start time point at the beginnig of the timer thread loop and sleep_until that time point after executing the function.

#include <iostream>
#include <chrono>
#include <thread>
#include <functional>

void timer_start(std::function<void(void)> func, unsigned int interval)
{
  std::thread([func, interval]()
  { 
    while (true)
    { 
      auto x = std::chrono::steady_clock::now() + std::chrono::milliseconds(interval);
      func();
      std::this_thread::sleep_until(x);
    }
  }).detach();
}

void do_something()
{
  std::cout << "I am doing something" << std::endl;
}

int main()
{
  timer_start(do_something, 1000);
  while (true)
    ;
}
查看更多
爷的心禁止访问
5楼-- · 2019-01-09 08:08

It depends on what you would be doing on per interval - displaying time/ticker or something else at specific location of screen/form. Or you may need to send regular data to some connected machine (over socket or pipe). Do you really need 10 millisecond precision?

Depending on requirement, especially the precision requirement, you may have dedicated thread to do 'something', then wait and do same thing again. Or, on Windows, you may use SetTimer that would trigger WM_TIMER event on each interval (it wouldn't require thread). You may also use waitable timer, multimedia timer etc.

At last, but quite important - Do you need platform and compiler compatibility? Meaning that, which OS you would be using, or you need platform independent? What compiler features you are looking for (C++11, C++14 or pre C++11).

查看更多
劫难
6楼-- · 2019-01-09 08:14

If you're coding with Visual C++, you could add a timer element to the form you want to call a periodic function (here it's called my form is MainForm, and my timer MainTimer). Add a call to the tick event in the "Events". The designer will add such line in your .h file:

this->MainTimer->Enabled = true;
this->MainTimer->Interval = 10;
this->MainTimer->Tick += gcnew System::EventHandler(this, &MainForm::MainTimer_Tick);

Then, at each interval (specified in ms), the application will call this function

private: System::Void MainTimer_Tick(System::Object^  sender, System::EventArgs^  e) {
   /// Enter your periodic code there
}
查看更多
Emotional °昔
7楼-- · 2019-01-09 08:22

You could look into threading:

Here's a time interval controlled function implemented in C, using pthread.h, it should be a simple port to C++. Executing a function at specific intervals

查看更多
登录 后发表回答