123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103 |
- #include <chrono>
- #include <functional>
- #include <list>
- #include <mutex>
- #include <thread>
- #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),
- wheel_(wheel_size),
- current_index_(0) {}
- ~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_));
- Tick();
- }
- std::cout << "timer oooops!" << std::endl;
- });
- thread_.detach();
- }
- void Stop() {
- if (!running_) {
- return;
- }
- running_ = false;
- if (thread_.joinable()) {
- 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++)
- {
- allindex = index * i;
- if (allindex >= wheel_size_)
- break;
- wheel_[allindex].push_back(task);
- }
-
- }
- 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_; /* 现在的时间点 */
- bool running_ = false;
- std::thread thread_;
- std::mutex mutex_;
- };
|