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

执行结果

相关推荐
List<String> error_P10 天前
STM32窗口看门狗WWDG详解
stm32·单片机·嵌入式硬件·定时器
youcans_10 天前
【动手学STM32G4】(13)STM32G431之 TIM+ADC
stm32·单片机·嵌入式硬件·定时器
List<String> error_P10 天前
独立看门狗IWDG原理详解
stm32·单片机·嵌入式硬件·定时器
List<String> error_P13 天前
定时器输出捕获与输入比较
stm32·定时器
List<String> error_P14 天前
STM32 Systick定时器介绍
stm32·定时器·systick
Da Da 泓15 天前
多线程(八)【定时器】
java·学习·多线程·定时器
ベadvance courageouslyミ18 天前
51单片机相关
单片机·51单片机·定时器·pwm·蜂鸣器·中断·独立按键
YouEmbedded20 天前
解码STM32定时器:原理、配置与实战
stm32·定时器·pwm·sg90舵机
youcans_24 天前
【动手学STM32G4】(8)STM32G431之 DAC进阶
stm32·单片机·嵌入式硬件·dma·定时器
BB8=_=NiMotion1 个月前
使用Codesys系统的控制器时,定时器的时间精度不够怎么办
定时器·codesys系统·时间精度