#pragma once
#include <chrono>
#include <vector>
#include <functional>
class Timer
{
public:
// 定时器回调函数类型
using TimerCallback = std::function<void()>;
// 默认构造函数
Timer();
// 析构函数
virtual ~Timer();
// 禁止拷贝和赋值操作
Timer(const Timer&) = delete;
Timer& operator=(const Timer&) = delete;
// 添加定时器
void addTimer(int timeout, TimerCallback callback);
// 删除定时器
void delTimer(const TimerCallback& callback);
// 处理超时定时器
void tick();
private:
// 定时器结构体
struct TimerNode
{
int id; // 定时器ID
int expire; // 定时器超时时间
TimerCallback callback; // 定时器回调函数
bool operator<(const TimerNode& t) const; // 应对小根堆的比较运算符
};
// 定时器ID计数器
int m_timer_count;
// 定时器堆
std::vector<TimerNode> m_heap;
// 添加定时器节点
void addTimerNode(const TimerNode& node);
// 删除定时器节点
void delTimerNode(int idx);
// 小根堆调整函数
void shiftDown(int start, int end);
};
#include "timer.h"
Timer::Timer() : m_timer_count(0)
{
}
Timer::~Timer()
{
}
void Timer::addTimer(int timeout, TimerCallback callback)
{
// 创建定时器节点
TimerNode node;
node.id = ++m_timer_count;
node.expire = std::chrono::steady_clock::now().time_since_epoch().count() + timeout * 1000; // 转换成毫秒
node.callback = callback;
// 添加定时器节点
this->addTimerNode(node);
}
void Timer::delTimer(const TimerCallback& callback)
{
// 找到对应的定时器节点
auto it = std::find_if(m_heap.begin(), m_heap.end(), [&callback](const TimerNode& node) { return node.callback == callback; });
if (it != m_heap.end())
{
// 删除定时器节点
this->delTimerNode(it - m_heap.begin());
}
}
void Timer::tick()
{
// 循环处理所有定时器节点
while (!m_heap.empty())
{
// 获取当前时间
auto now = std::chrono::steady_clock::now().time_since_epoch().count();
// 判断是否超时
if (now >= m_heap[0].expire)
{
// 调用定时器回调函数
m_heap[0].callback();
// 删除定时器节点
this->delTimerNode(0);
}
else
{
// 堆第一个元素未过期,退出循环
break;
}
}
}
void Timer::addTimerNode(const TimerNode& node)
{
// 将节点插入堆尾
m_heap.push_back(node);
// 小根堆调整操作
int start = (m_heap.size() - 2) / 2;
int end = m_heap.size() - 1;
while (start >= 0)
{
this->shiftDown(start, end);
--start;
}
}
void Timer::delTimerNode(int idx)
{
// 将堆尾元素移到要删除的元素位置
m_heap[idx] = m_heap.back();
m_heap.pop_back();
// 小根堆调整操作
int start = idx;
int end = m_heap.size() - 1;
int parent = (start - 1) / 2;
if (m_heap[parent] < m_heap[start])
{
this->shiftDown(start, end);
}
else
{
while (start > 0 && !(m_heap[parent] < m_heap[start]))
{
std::swap(m_heap[start], m_heap[parent]);
start = parent;
parent = (start - 1) / 2;
}
}
}
void Timer::shiftDown(int start, int end)
{
int root = start;
while (root * 2 + 1 <= end)
{
int child = root * 2 + 1;
if (child + 1 <= end && m_heap[child] > m_heap[child + 1])
{
child = child + 1;
}
if (m_heap[root] > m_heap[child])
{
std::swap(m_heap[root], m_heap[child]);
root = child;
}
else
{
return;
}
}
}
bool Timer::TimerNode::operator<(const TimerNode& t) const
{
return this->expire < t.expire;
}
使用该定时器时,只需要在你自己的代码中包含这个头文件,然后创建一个 Timer 实例即可。每次需要添加定时器时,调用 addTimer() 方法添加一个指定超时时间和回调函数的定时器即可。定时器的回调函数会在定时器超时时被自动调用。
以下是一些使用定时器的示例代码:
#include "timer.h"
void printMessage()
{
std::cout << "Hello, world!\n";
}
int main()
{
Timer timer;
// 添加定时器
timer.addTimer(1, []() { std::cout << "Timeout 1s\n"; });
timer.addTimer(2, []() { std::cout << "Timeout 2s\n"; });
timer.addTimer(5, []() { std::cout << "Timeout 5s\n"; });
// 添加回调函数定时器
timer.addTimer(3, std::bind(&printMessage));
while (true)
{
// 处理定时器
timer.tick();
}
return 0;
}
对于项目的建议,如果只是觉得现有的基于升序链表的定时器不够高效,就不必着急更换。定时器是一个非常基础的模块,原则上应该保证其可靠性和正确性,不要为了快速换取一些微小的性能提升而引入更复杂的实现。当项目的性能瓶颈确实在定时器上时,再考虑采用类似小根堆的高效实现。