C++定时器的实现之格式修订版

个人认为一个完备的定时器需要有如下功能:

  • 在某一时间点执行某一任务

  • 在某段时间后执行某一任务

  • 重复执行某一任务N次,任务间隔时间T

那么如何实现定时器呢?下面是我自己实现的定时器逻辑,源码链接最后会附上。

定时器中主要的数据结构

  • 优先级任务队列:队列中存储任务,每个任务会添加时间戳,最近的时间戳的任务会先出队。

  • 锁和条件变量:当有任务需要执行时,用于通知正在等待的线程从任务队列中取出任务执行。

  • 线程池:各个任务会放在线程池中执行。

下面是相关代码:

class TimerQueue {public:  struct InternalS {      std::chrono::time_point<std::chrono::high_resolution_clock> time_point_;      std::function<void()> func_;      bool operator<(const InternalS& b) const { return time_point_ > b.time_point_; }  };  enum class RepeatedIdState { kInit = 0, kRunning = 1, kStop = 2 };
private:  std::priority_queuequeue_;  bool running_ = false;  std::mutex mutex_;  std::condition_variable cond_;
  wzq::ThreadPool thread_pool_;
  std::atomic<int> repeated_func_id_;  wzq::ThreadSafeMap<int, RepeatedIdState> repeated_id_state_map_;};

如何开启定时器功能

打开内部的线程池功能,用于执行放入定时器中的任务,同时新开一个线程,循环等待任务到来后送入线程池中执行。

bool Run() {    bool ret = thread_pool_.Start();    if (!ret) {        return false;    }    std::thread([this]() { RunLocal(); }).detach();    return true;}
void RunLocal() {    while (running_) {        std::unique_lock<std::mutex> lock(mutex_);        if (queue_.empty()) {            cond_.wait(lock);            continue;        }        auto s = queue_.top();        auto diff = s.time_point_ - std::chrono::high_resolution_clock::now();        if (std::chrono::duration_cast<std::chrono::milliseconds>(diff).count() > 0) {            cond_.wait_for(lock, diff);            continue;        } else {            queue_.pop();            lock.unlock();            thread_pool_.Run(std::move(s.func_));        }    }}

如何在某一时间点执行任务

根据时间戳构造InternalS,放入队列中:

template <typename F, typename... Args>
void AddFuncAtTimePoint(const std::chrono::time_point<std::chrono::high_resolution_clock>& time_point, F&& f,                        Args&&... args) {    InternalS s;    s.time_point_ = time_point;    s.func_ = std::bind(std::forward(f), std::forward(args)...);    std::unique_lock<std::mutex> lock(mutex_);    queue_.push(s);    cond_.notify_all();}

如何循环执行任务

首先为这个循环任务生成标识ID,外部可以通过ID来取消此任务继续执行,代码如下,内部以类似递归的方式循环执行任务。

template <typename R, typename P, typename F, typename... Args>int AddRepeatedFunc(int repeat_num, const std::chrono::duration& time, F&& f, Args&&... args) {    int id = GetNextRepeatedFuncId();    repeated_id_state_map_.Emplace(id, RepeatedIdState::kRunning);    auto tem_func = std::bind(std::forward(f), std::forward(args)...);    AddRepeatedFuncLocal(repeat_num - 1, time, id, std::move(tem_func));    return id;}
int GetNextRepeatedFuncId() { return repeated_func_id_++; }
template <typename R, typename P, typename F>void AddRepeatedFuncLocal(int repeat_num, const std::chrono::duration& time, int id, F&& f) {    if (!this->repeated_id_state_map_.IsKeyExist(id)) {        return;    }    InternalS s;    s.time_point_ = std::chrono::high_resolution_clock::now() + time;    auto tem_func = std::move(f);    s.repeated_id = id;    s.func_ = [this, &tem_func, repeat_num, time, id]() {        tem_func();        if (!this->repeated_id_state_map_.IsKeyExist(id) || repeat_num == 0) {            return;        }        AddRepeatedFuncLocal(repeat_num - 1, time, id, std::move(tem_func));    };    std::unique_lock<std::mutex> lock(mutex_);    queue_.push(s);    lock.unlock();    cond_.notify_all();}

声明:

本文于网络整理,版权归原作者所有,如来源信息有误或侵犯权益,请联系我们删除或授权事宜。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值