How to install a reoccurring timer function?

让人想犯罪 __ 提交于 2019-12-23 04:34:01

问题


Is there a simple way to install a regularly occurring timer function with C++/stdlib? I would like to get rid of the loop:

using namespace std::chrono; // literal suffixes
auto tNext = steady_clock::now();
while (<condition>) {
    std::this_thread::sleep_until(tNext);
    tNext = tNext + 100ms; 
    ...

That function will run in its own thread.


回答1:


I'm guessing what you want is this

int i = 10;
auto pred = [i]() mutable {return i--;};
auto print = []{cout << "." << endl;};

timer t{500ms};
t.push({print, pred});  //asynchronously prints '.' 10 times within 5s

//do anything else

Assuming performance is not critical and the timer is not often updated, the following should provide ample functionality.

#include<functional>
#include<vector>
#include<thread>
#include<utility>
#include<chrono>
#include<mutex>
#include<atomic>

class timer final
{
public:
    using microseconds = std::chrono::microseconds;

    using predicate = std::function<bool ()>;
    using callback = std::function<void ()>;
    using job = std::pair<callback, predicate>;

    explicit timer(microseconds t) : done{false}, period{t}
    {
        std::lock_guard<std::mutex> lck(mtx);

        worker = std::thread([this]{
            auto t = std::chrono::steady_clock::now();
            while(!done.load())
            {
                std::this_thread::sleep_until(t);
                std::lock_guard<std::mutex> lck(mtx);
                t += period;
                for(auto it = jobs.begin(); it != jobs.end();)
                {
                    if(it->second())
                        it++->first();
                    else
                        it = jobs.erase(it);
                }
            }
        });
    }

    ~timer()
    {
        done.store(true);
        worker.join();
    }

    void set_period(microseconds t)
    {
        std::lock_guard<std::mutex> lck(mtx);
        period = t;
    }
    void push(const callback& c)
    {
        std::lock_guard<std::mutex> lck(mtx);
        jobs.emplace_back(c, []{return true;});
    }
    void push(const job& j)
    {
        std::lock_guard<std::mutex> lck(mtx);
        jobs.push_back(j);
    }

private:
    std::mutex mtx;
    std::atomic_bool done;
    std::thread worker;

    std::vector<job> jobs;
    microseconds period;
};

timer calls previously pushed callbacks periodically, and when predicate evaluates to false, deletes the callback from the timer. The timer object has its own lifetime and its worker thread will only live as long as it is alive.

The reason you would want to have multiple jobs in a single timer is so that they would be called together, using only one thread and be in sync with each other.

Don't worry about the mutex unless you are planning to update the timer >10,000 times a second, have a period of <1ms or have very time-consuming callbacks.



来源:https://stackoverflow.com/questions/43632280/how-to-install-a-reoccurring-timer-function

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!