TimerWheel.h 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103
  1. #include <chrono>
  2. #include <functional>
  3. #include <list>
  4. #include <mutex>
  5. #include <thread>
  6. #include <vector>
  7. #include <iostream>
  8. /**
  9. * @brief 这是一个时间轮定时器的实现,将任务添加到时间轮中,时间轮会在指定的时间点执行任务
  10. * 任务是一个函数对象,可以是lambda表达式,也可以是std::bind绑定的函数
  11. * 任务是挂在一个个时间点上的,同一个时间点可以有多个任务,时间点的最大数目就是任务容器最大容量
  12. *
  13. * 缺点:
  14. * 1、时间轮的时间点是固定的,如果任务的时间点不在时间轮的时间点上,就会被延迟执行
  15. * 2、任务执行是在这个线程中执行的,如果任务执行时间过长,会影响时间轮的执行
  16. */
  17. class TimerWheel {
  18. public:
  19. using Task = std::function<void()>;
  20. /* 构造函数,第一个参数是任务时间点容器最大数量,第二个参数是最低检测时间单位 */
  21. explicit TimerWheel(size_t wheel_size, int interval_ms)
  22. : wheel_size_(wheel_size),
  23. interval_ms_(interval_ms),
  24. wheel_(wheel_size),
  25. current_index_(0) {}
  26. ~TimerWheel() {
  27. Stop();
  28. }
  29. /* 开启时间轮 */
  30. void Start() {
  31. if (running_) {
  32. return;
  33. }
  34. running_ = true;
  35. /* 开启新线程,定时检测队列 */
  36. thread_ = std::thread([this]() {
  37. while (running_) {
  38. std::this_thread::sleep_for(std::chrono::milliseconds(interval_ms_));
  39. Tick();
  40. }
  41. std::cout << "timer oooops!" << std::endl;
  42. });
  43. thread_.detach();
  44. }
  45. void Stop() {
  46. if (!running_) {
  47. return;
  48. }
  49. running_ = false;
  50. if (thread_.joinable()) {
  51. thread_.join();
  52. }
  53. }
  54. /* 添加任务函数 */
  55. void AddTask(int timeout_ms, Task task) {
  56. std::lock_guard<std::mutex> lock(mutex_);
  57. /* 计算出需要轮训的次数 */
  58. size_t ticks = timeout_ms / interval_ms_;
  59. /* 在当前时间点上加上ticks */
  60. size_t index = (current_index_ + ticks) % wheel_size_;
  61. /* 这里是设置在整个时间轮中,该任务在这个时间轮中的分布,以实现循环定时 */
  62. size_t allindex = index;
  63. for (size_t i = 1 ; allindex < wheel_size_; i++)
  64. {
  65. allindex = index * i;
  66. if (allindex >= wheel_size_)
  67. break;
  68. wheel_[allindex].push_back(task);
  69. }
  70. }
  71. private:
  72. /* 时间片 */
  73. void Tick() {
  74. std::lock_guard<std::mutex> lock(mutex_);
  75. /* 取出这个时间点的函数,循环执行 */
  76. auto& tasks = wheel_[current_index_];
  77. for (const auto& task : tasks) {
  78. task();
  79. }
  80. //tasks.clear();
  81. /* 可以循环定时的关键,超过了设置的最大时间点,就会重置 */
  82. current_index_ = (current_index_ + 1) % wheel_size_;
  83. }
  84. private:
  85. size_t wheel_size_; /* 时间轮最大的轮训次数 */
  86. int interval_ms_; /* 每个时间点的间隔秒数 */
  87. std::vector<std::list<Task>> wheel_; /* 任务队列,同一个时间点可以有多个链表 */
  88. size_t current_index_; /* 现在的时间点 */
  89. bool running_ = false;
  90. std::thread thread_;
  91. std::mutex mutex_;
  92. };