#include #include #include #include #include #include #include #include "ThreadPool.h" #include "spdlog/spdlog.h" #include "RingQueue.hpp" /** * @brief 这是一个时间轮定时器的实现,将任务添加到时间轮中,时间轮会在指定的时间点执行任务 * 任务是一个函数,可以是lambda表达式,也可以是std::bind绑定的函数 * 任务是挂在一个个时间点上的,同一个时间点可以有多个任务,时间点的最大数目就是任务容器最大容量 * 间隔时间是1ms,最大定时时间是1000 * 60 * 60 ms,也就是1小时 * * 缺点: * 1、时间轮的时间点是固定的,如果任务的时间点不在时间轮的时间点上,就会被延迟执行 * 2、任务执行是在这个线程中执行的,如果任务执行时间过长,会影响时间轮的执行 */ /** ================================================================== * * ================================================================== */ /* 定义函数指针 */ using TaskFunc = std::function; /* 定义任务结构体 */ struct Task { bool is_loop; /* 是否循环定时 */ TaskFunc func; /* 任务函数 */ long interval; /* 定时间隔 */ }; class TimerWheel { public: /* 构造函数,第一个参数是任务时间点容器最大数量,第二个参数是最低检测时间单位 */ explicit TimerWheel() : m_current_index(0) { m_wheel_size = 1000 * 60 * 60; /* 1小时 */ m_interval_ms = 1000; /* 1ms */ m_firstLevelWheel.resize(1000); m_secondLevelWheel.resize(60); m_thirdLevelWheel.resize(60); } ~TimerWheel() { Stop(); } /* 开启时间轮 */ void Start() { if (m_running) { return; } m_running = true; /* 开启新线程,定时检测队列 */ m_thread = std::thread([this]() { while (m_running) { std::this_thread::sleep_for(std::chrono::milliseconds(m_interval_ms)); Tick(); } std::cout << "timer oooops!" << std::endl; }); m_thread.detach(); } void Stop() { if (!m_running) { return; } m_running = false; if (m_thread.joinable()) { m_thread.join(); } } /* 添加任务函数 */ void AddTask(int timeout_ms, Task task, bool is_loop = false) { std::lock_guard lock(mutex_); /* 计算出需要轮训的次数 */ size_t ticks = timeout_ms / m_interval_ms; /* 在当前时间点上加上ticks */ size_t index = (m_current_index + ticks) % m_wheel_size; /* 这里是设置在整个时间轮中,该任务在这个时间轮中的分布,以实现循环定时 */ size_t allindex = index; for (size_t i = 1 ; allindex < m_wheel_size; i++) { allindex = index * i; if (allindex >= m_wheel_size) break; wheel_[allindex].push_back(task); } } private: /* 时间片 */ void Tick() { std::lock_guard lock(mutex_); /* 取出这个时间点的函数,循环执行 */ auto& tasks = wheel_[m_current_index]; for (const auto& task : tasks) { task(); } //tasks.clear(); /* 可以循环定时的关键,超过了设置的最大时间点,就会重置 */ m_current_index = (m_current_index + 1) % m_wheel_size; } private: long m_max_interval = 0; /* 最大的定时时间长度,等于下面两个之和,超过就报错 */ size_t m_wheel_size; /* 时间轮最大的轮训次数 */ int m_interval_ms; /* 每个时间点的间隔秒数,这里是1ms */ long m_firstLevelCount; /* 第一层级的时间轮的个数 */ long m_secondLevelCount; /* 第二层级的时间轮的个数 */ long m_thirdLevelCount; /* 第三层级的时间轮的个数 */ std::vector> m_firstLevelWheel; /* 第一层级的时间轮,这里是ms等级,总共1000个 */ std::vector> m_secondLevelWheel; /* 第二层级的时间轮,这里是秒的等级,总共60个 */ std::vector> m_thirdLevelWheel; /* 第三层级的时间轮,这里是分钟的等级,总共60个 */ size_t m_current_index; /* 现在的时间点 */ bool m_running = false; /* 运行标识位 */ std::thread m_thread; std::mutex mutex_; };