C++一个简单的定时器

0.前言

C++学习笔记。

该学习笔记练习使用了 std::function 函数对象,std::bind 函数适配器,std::priority_queue 创建最大堆,std::mutex 创建互斥锁,std::condition_variable 条件变量。

1.正文

C++实现一个简单的定时器任务,可以添加定时器。

cpp 复制代码
#include <iostream>
#include <string>
#include <chrono>
#include <mutex>
#include <condition_variable>
#include <vector>
#include <queue>
#include <thread>
#include <functional>
#include <cstdint>


using SteadyClock = std::chrono::steady_clock;
using TimePoint = std::chrono::steady_clock::time_point;
using MillionSecond = std::chrono::milliseconds;

class TimerTask {
 public:
  using TimerFunc = std::function<void(const TimerTask & timer)>;

  enum {
    TIMER_TASK_PERIOD,
    TIMER_TASK_ONESHOT,
  };

  uint32_t id_;
  int type_;
  MillionSecond interval_;
  TimePoint trigger_point_;
  TimerFunc func_;
};

class TimerCompare {
 public:
  bool operator()(const TimerTask &a, const TimerTask &b) {
    return a.trigger_point_ > b.trigger_point_;
  }
};

class TimerTaskThread {
 public:
  int add(bool oneshot, int interval_ms, const TimerTask::TimerFunc &func) 
  {
    TimerTask timer;
    timer.type_ = oneshot ? TimerTask::TIMER_TASK_ONESHOT : TimerTask::TIMER_TASK_PERIOD;
    timer.interval_ = MillionSecond(interval_ms);
    timer.trigger_point_ = SteadyClock::now() + timer.interval_;
    timer.func_ = func;
   
    {
      std::unique_lock<std::mutex> lock;
      timer.id_ = id_pool_++;
      timer_queue_.push(timer);
      cv_notify_.notify_one();
    }

    return timer.id_ ;
  }

  int remove(int id) {
    std::unique_lock<std::mutex> lock;
    std::vector<TimerTask> temp;

    while(!timer_queue_.empty()) {
      auto timer = timer_queue_.top();
      timer_queue_.pop();

      if(timer.id_ == id) {
        continue;
      }

      temp.push_back(timer);
    }

    for(auto timer : temp) {
      timer_queue_.push(timer);
    }

    cv_notify_.notify_one();

    return 0;
  }

  TimePoint top(void) {
    if(timer_queue_.empty()) {
      return TimePoint::max();
    }

    return timer_queue_.top().trigger_point_;
  }

  TimePoint now(void) {
    return SteadyClock::now();
  }

  void start(void) {
    running_ = true;
    // std::thread([this](){
    //   run();
    // }).detach();

    std::thread(&TimerTaskThread::run, this).detach();

  }

  void process_timer(TimerTask &timer) {
    timer.func_(timer);

    if(timer.type_ == TimerTask::TIMER_TASK_PERIOD) {
      timer.trigger_point_ = SteadyClock::now() + timer.interval_;
      timer_queue_.push(timer);
    }
  }

  void run(void) {
    while(running_) {
      std::unique_lock<std::mutex> lock(mutex_);

      cv_notify_.wait_until(lock, top());
      
      while(!timer_queue_.empty() && now() >= top()) {
        if(!running_)
          break;
        
        auto timer = timer_queue_.top();
        timer_queue_.pop();
        process_timer(timer);
      }
    }
  }


 void dump()
 {
  std::cout << "timertaskthread dump" << std::endl;
 }

 private:
  using PriorityQueue = std::priority_queue<TimerTask, std::vector<TimerTask>, TimerCompare>;
  PriorityQueue timer_queue_;
  int running_;
  std::mutex mutex_;
  std::condition_variable cv_notify_;
  uint32_t id_pool_;
};


int main(int argc, char *argv[]) {
  TimerTaskThread timer_task;
  timer_task.start();

  std::cout << std::chrono::steady_clock::now().time_since_epoch().count() << std::endl;

  timer_task.add(false, 2000, [](const TimerTask & timer) {
    std::cout << std::chrono::steady_clock::now().time_since_epoch().count() << std::endl;
    std::cout << "timer task 1" << std::endl;
    });
  
  timer_task.add(false, 2000, [](const TimerTask & timer) {
    std::cout << std::chrono::steady_clock::now().time_since_epoch().count() << std::endl;
    std::cout << "timer task 1" << std::endl;
    });

  timer_task.add(false, 4000, [](const TimerTask & timer) {
    std::cout << std::chrono::steady_clock::now().time_since_epoch().count() << std::endl;
    std::cout << "timer task 2" << std::endl;
    });
  
  
  auto fun1 = std::bind(&TimerTaskThread::dump, &timer_task);
  int timer_id_1 = timer_task.add(false, 200, fun1);
  
  int count = 0;
  while(1) {
    std::this_thread::sleep_for(std::chrono::seconds(1));
    count++;
    if(count == 2) {
      timer_task.remove(timer_id_1);
    }
  }


  return 0;
}

执行结果

相关推荐
阿钱真强道5 天前
18 嵌入式操作系统 | uloop 定时器:周期任务与网络上报
c语言·定时器·周期任务·uloop
晊晌_h6 天前
IMX6ULL裸机开发:定时器(GPT/EPIT)与UART串口
arm·定时器·arm裸机开发
AAA代码批发商11 天前
Days 50 51 单片机与 i.MX6ULL 定时器对比:Timer、EPIT、GPT 原理与实验
51单片机·定时器·imx6ull·裸机开发
捷瑞电子工坊12 天前
蓝桥杯嵌入式STM32G431定时器入门:从原理到CubeMX配置(LL库)
cubemx·定时器·定时中断·led闪烁·蓝桥杯嵌入式·stm32g431·ll库
阿钱真强道1 个月前
24 极物科技 | DALI协议栈 - 定时器与中断系统
定时器·曼彻斯特编码·极物·极物智能·极物科技·dali协议栈·智慧照明
jufeng13071 个月前
STM32F103 定时器输入捕获实战:测频测周、编码器测速、红外解码全流程拆解
stm32·输入捕获·定时器·编码器
啦啦啦啦啦zzzz1 个月前
时间轮定时器
linux·服务器·网络·c++·定时器
保安大队王队长2 个月前
定时器知识
定时器
Dlrb12112 个月前
ARM---IMX6ULL定时器详解与应用:EPIT与GPT定时器,高精度延时函数
arm开发·gpt·arm·定时器·epit·高精度延时
名字还没想好☜2 个月前
Go 的 time.Ticker 陷阱:定时任务里被忽略的内存泄漏与正确关闭
java·数据库·golang·go·定时器