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;
}

执行结果

相关推荐
咬_咬8 天前
Linux时间轮定时器
linux·运维·网络·定时器·timerfd
DebugKitty1 个月前
硬件开发2-ARM裸机开发3-I.MX6ULL - 时钟、定时器
arm开发·fpga开发·定时器·时钟
逼子格2 个月前
【Proteus仿真】定时器控制系列仿真——秒表计数/数码管显示时间
数据库·单片机·嵌入式硬件·51单片机·proteus·定时器·硬件工程师
Rysxt_2 个月前
开源定时器教程:Quartz与XXL-JOB全面对比与实践
开源·定时器
眰恦ゞLYF2 个月前
51单片机:中断、定时器与PWM整合手册
定时器·中断系统
sheepwjl2 个月前
《嵌入式硬件(二):中断》
定时器·pwm·中断·按键·中断寄存器
逼子格2 个月前
【Protues仿真】基于AT89C52单片机的温湿度测量
单片机·嵌入式硬件·定时器·硬件工程师·dht11·温湿度传感器·at89c52
逼子格2 个月前
【Proteus仿真】8*8LED点阵控制系列仿真——循环显示数字/按键控制显示图案
单片机·嵌入式硬件·proteus·嵌入式·定时器·硬件工程师·led点阵
逼子格2 个月前
【Protues仿真】定时器
单片机·嵌入式硬件·51单片机·定时器·硬件工程师·硬件工程师真题·at89c52