123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132 |
- #include <chrono>
- #include <functional>
- #include <list>
- #include <mutex>
- #include <thread>
- #include <vector>
- #include <iostream>
- #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<void()>;
- /* 定义任务结构体 */
- 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<std::mutex> 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<std::mutex> 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<std::list<Task>> m_firstLevelWheel; /* 第一层级的时间轮,这里是ms等级,总共1000个 */
- std::vector<std::list<Task>> m_secondLevelWheel; /* 第二层级的时间轮,这里是秒的等级,总共60个 */
- std::vector<std::list<Task>> m_thirdLevelWheel; /* 第三层级的时间轮,这里是分钟的等级,总共60个 */
- size_t m_current_index; /* 现在的时间点 */
- bool m_running = false; /* 运行标识位 */
- std::thread m_thread;
- std::mutex mutex_;
-
- };
|