|  | @@ -7,10 +7,20 @@
 | 
	
		
			
				|  |  |  #include <vector>
 | 
	
		
			
				|  |  |  #include <iostream>
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | +/**
 | 
	
		
			
				|  |  | + * @brief 这是一个时间轮定时器的实现,将任务添加到时间轮中,时间轮会在指定的时间点执行任务
 | 
	
		
			
				|  |  | + *        任务是一个函数对象,可以是lambda表达式,也可以是std::bind绑定的函数
 | 
	
		
			
				|  |  | + *        任务是挂在一个个时间点上的,同一个时间点可以有多个任务,时间点的最大数目就是任务容器最大容量
 | 
	
		
			
				|  |  | + * 
 | 
	
		
			
				|  |  | + * 缺点:
 | 
	
		
			
				|  |  | + *        1、时间轮的时间点是固定的,如果任务的时间点不在时间轮的时间点上,就会被延迟执行
 | 
	
		
			
				|  |  | + *        2、任务执行是在这个线程中执行的,如果任务执行时间过长,会影响时间轮的执行
 | 
	
		
			
				|  |  | + */
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  |  class TimerWheel {
 | 
	
		
			
				|  |  |  public:
 | 
	
		
			
				|  |  |      using Task = std::function<void()>;
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | +    /* 构造函数,第一个参数是任务时间点容器最大数量,第二个参数是最低检测时间单位 */
 | 
	
		
			
				|  |  |      explicit TimerWheel(size_t wheel_size, int interval_ms)
 | 
	
		
			
				|  |  |          : wheel_size_(wheel_size),
 | 
	
		
			
				|  |  |          interval_ms_(interval_ms),
 | 
	
	
		
			
				|  | @@ -20,12 +30,13 @@ public:
 | 
	
		
			
				|  |  |      ~TimerWheel() {
 | 
	
		
			
				|  |  |          Stop();
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | +    /* 开启时间轮 */
 | 
	
		
			
				|  |  |      void Start() {
 | 
	
		
			
				|  |  |          if (running_) {
 | 
	
		
			
				|  |  |              return;
 | 
	
		
			
				|  |  |          }
 | 
	
		
			
				|  |  |          running_ = true;
 | 
	
		
			
				|  |  | +        /* 开启新线程,定时检测队列 */
 | 
	
		
			
				|  |  |          thread_ = std::thread([this]() {
 | 
	
		
			
				|  |  |              while (running_) {
 | 
	
		
			
				|  |  |                  std::this_thread::sleep_for(std::chrono::milliseconds(interval_ms_));
 | 
	
	
		
			
				|  | @@ -45,11 +56,14 @@ public:
 | 
	
		
			
				|  |  |              thread_.join();
 | 
	
		
			
				|  |  |          }
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | +    /* 添加任务函数 */
 | 
	
		
			
				|  |  |      void AddTask(int timeout_ms, Task task) {
 | 
	
		
			
				|  |  |          std::lock_guard<std::mutex> lock(mutex_);
 | 
	
		
			
				|  |  | +        /* 计算出需要轮训的次数 */
 | 
	
		
			
				|  |  |          size_t ticks = timeout_ms / interval_ms_;
 | 
	
		
			
				|  |  | +        /* 在当前时间点上加上ticks */
 | 
	
		
			
				|  |  |          size_t index = (current_index_ + ticks) % wheel_size_;
 | 
	
		
			
				|  |  | +        /* 这里是设置在整个时间轮中,该任务在这个时间轮中的分布,以实现循环定时 */
 | 
	
		
			
				|  |  |          size_t allindex = index;
 | 
	
		
			
				|  |  |          for (size_t i = 1 ; allindex < wheel_size_; i++)
 | 
	
		
			
				|  |  |          {
 | 
	
	
		
			
				|  | @@ -62,21 +76,24 @@ public:
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  private:
 | 
	
		
			
				|  |  | +    /* 时间片 */
 | 
	
		
			
				|  |  |      void Tick() {
 | 
	
		
			
				|  |  |          std::lock_guard<std::mutex> lock(mutex_);
 | 
	
		
			
				|  |  | +        /* 取出这个时间点的函数,循环执行 */
 | 
	
		
			
				|  |  |          auto& tasks = wheel_[current_index_];
 | 
	
		
			
				|  |  |          for (const auto& task : tasks) {
 | 
	
		
			
				|  |  |              task();
 | 
	
		
			
				|  |  |          }
 | 
	
		
			
				|  |  |          //tasks.clear();
 | 
	
		
			
				|  |  | +        /* 可以循环定时的关键,超过了设置的最大时间点,就会重置 */
 | 
	
		
			
				|  |  |          current_index_ = (current_index_ + 1) % wheel_size_;
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  private:
 | 
	
		
			
				|  |  | -    size_t wheel_size_;
 | 
	
		
			
				|  |  | -    int interval_ms_;
 | 
	
		
			
				|  |  | -    std::vector<std::list<Task>> wheel_;
 | 
	
		
			
				|  |  | -    size_t current_index_;
 | 
	
		
			
				|  |  | +    size_t wheel_size_;                     /* 时间轮最大的轮训次数 */
 | 
	
		
			
				|  |  | +    int interval_ms_;                       /* 每个时间点的间隔秒数 */
 | 
	
		
			
				|  |  | +    std::vector<std::list<Task>> wheel_;    /* 任务队列,同一个时间点可以有多个链表 */
 | 
	
		
			
				|  |  | +    size_t current_index_;                  /* 现在的时间点 */
 | 
	
		
			
				|  |  |      bool running_ = false;
 | 
	
		
			
				|  |  |      std::thread thread_;
 | 
	
		
			
				|  |  |      std::mutex mutex_;
 |