Timer
计时器类,其内部维护了循环周期和回调函数,以及下一次应该被执行的时间节点
成员变量
1 2 3 4 5 6 7 8 9 10 11 12 13
| class Timer : public std::enable_shared_from_this<Timer> { friend class TimerManager; private: bool m_recurring = false; uint64_t m_ms = 0; uint64_t m_next = 0; std::function<void()> m_cb; TimerManager* m_manager = nullptr; private: struct Comparator { bool operator()(const Timer::ptr& lhs, const Timer::ptr& rhs) const; }; };
|
构造函数
两个构造函数都是私有的构造函数,只能被TimeManager
调用
1 2 3 4 5 6 7 8 9 10 11 12
| Timer::Timer(uint64_t ms, std::function<void()> cb, bool recurring, TimerManager* manager) :m_recurring(recurring) , m_ms(ms) , m_cb(cb) , m_manager(manager) { m_next = sylar::GetCurrentMS() + m_ms; }
Timer::Timer(uint64_t next) :m_next(next) { }
|
成员函数
1 2 3 4 5 6 7 8 9 10 11 12
| class Timer : public std::enable_shared_from_this<Timer> { friend class TimerManager; public: typedef std::shared_ptr<Timer> ptr; bool cancel(); bool refresh(); bool reset(uint64_t ms, bool from_now); private: Timer(uint64_t ms, std::function<void()> cb, bool recurring, TimerManager* manager); Timer(uint64_t next); };
|
cancel
从TimerManager
管理的队列中删除Timer
,并且将该Timer
的回调设置为空
1 2 3 4 5 6 7 8 9 10 11 12
| bool Timer::cancel() { TimerManager::RWMutexType::WriteLock lock(m_manager->m_mutex); if (m_cb) { m_cb = nullptr; auto it = m_manager->m_timers.find(shared_from_this()); m_manager->m_timers.erase(it); return true; } return false; }
|
refresh
刷新计时器的计时时间
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| bool Timer::refresh() { TimerManager::RWMutexType::WriteLock lock(m_manager->m_mutex); if (!m_cb) { return false; } auto it = m_manager->m_timers.find(shared_from_this()); if (it == m_manager->m_timers.end()) { return false; } m_manager->m_timers.erase(it); m_next = sylar::GetCurrentMS() + m_ms; m_manager->m_timers.insert(shared_from_this()); return true; }
|
reset
重置定时器的执行时间间隔
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
| bool Timer::reset(uint64_t ms, bool from_now) { if (ms == m_ms && !from_now) { return true; } TimerManager::RWMutexType::WriteLock lock(m_manager->m_mutex); if (!m_cb) { return false; } auto it = m_manager->m_timers.find(shared_from_this()); if (it == m_manager->m_timers.end()) { return false; } m_manager->m_timers.erase(it); uint64_t start = 0; if (from_now) { start = sylar::GetCurrentMS(); } else { start = m_next - m_ms; } m_ms = ms; m_next = start + m_ms; m_manager->addTimer(shared_from_this(), lock); return true; }
|
TimerManager
内部维护了一个m_timers
定时器集合,用于管理这些定时器,其中listExpiredCb
是核心函数,该函数检测当前时间是否已经到达定时器设定的时间,并通过传入传出参数使调用者获取定时器中的回调函数cb
成员变量
1 2 3 4 5 6 7 8
| class TimerManager { friend class Timer; private: RWMutexType m_mutex; std::set<Timer::ptr, Timer::Comparator> m_timers; bool m_tickled = false; uint64_t m_previouseTime = 0; };
|
构造函数
1 2 3 4 5 6
| TimerManager::TimerManager() { m_previouseTime = sylar::GetCurrentMS(); }
TimerManager::~TimerManager() { }
|
仅该文件可见的static静态函数
用于满足条件回调函数,只有传入的指针还存在时,才执行对应的回调函数
1 2 3 4 5 6
| static void OnTimer(std::weak_ptr<void> weak_cond, std::function<void()> cb) { std::shared_ptr<void> tmp = weak_cond.lock(); if (tmp) { cb(); } }
|
成员函数
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| class TimerManager { friend class Timer; public: Timer::ptr addTimer(uint64_t ms, std::function<void()> cb , bool recurring = false); Timer::ptr addConditionTimer(uint64_t ms, std::function<void()> cb , std::weak_ptr<void> weak_cond , bool recurring = false); uint64_t getNextTimer(); void listExpiredCb(std::vector<std::function<void()> >& cbs); bool hasTimer(); protected: virtual void onTimerInsertedAtFront() = 0; void addTimer(Timer::ptr val, RWMutexType::WriteLock& lock); private: bool detectClockRollover(uint64_t now_ms); };
|
addTimer
public方法:向内部维护的set
中添加一个Timer
对象,并给外部返回这个Timer
指针
1 2 3 4 5 6 7
| Timer::ptr TimerManager::addTimer(uint64_t ms, std::function<void()> cb , bool recurring) { Timer::ptr timer(new Timer(ms, cb, recurring, this)); RWMutexType::WriteLock lock(m_mutex); addTimer(timer, lock); return timer; }
|
protected方法:直接传入Timer
对象,并将其添加到set
中,需要额外判断是否在队列最前端,并调用onTimerInsertedAtFront()
方法
1 2 3 4 5 6 7 8 9 10 11 12
| void TimerManager::addTimer(Timer::ptr val, RWMutexType::WriteLock& lock) { auto it = m_timers.insert(val).first; bool at_front = (it == m_timers.begin()) && !m_tickled; if (at_front) { m_tickled = true; } lock.unlock();
if (at_front) { onTimerInsertedAtFront(); } }
|
addConditionTimer
添加条件计时器,内部实际上还是调用addTimer
方法,但调用时会检查weak_cond
指针是否存在,如果存在才调用回调cb
1 2 3 4 5
| Timer::ptr TimerManager::addConditionTimer(uint64_t ms, std::function<void()> cb , std::weak_ptr<void> weak_cond , bool recurring) { return addTimer(ms, std::bind(&OnTimer, weak_cond, cb), recurring); }
|
getNextTimer
获取到最近一个定时器执行的时间间隔
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| uint64_t TimerManager::getNextTimer() { RWMutexType::ReadLock lock(m_mutex); m_tickled = false; if (m_timers.empty()) { return ~0ull; } const Timer::ptr& next = *m_timers.begin(); uint64_t now_ms = sylar::GetCurrentMS(); if (now_ms >= next->m_next) { return 0; } else { return next->m_next - now_ms; } }
|
detectClockRollover
检查是否发生时间会绕,即时间突然从很大的值变成很小的值,在重启或手动调整时间时可能发生
检查当前时间 now_ms
是否小于上一次记录的时间 m_previouseTime
,并且 now_ms
是否小于 m_previouseTime
减去一小时(即 60 * 60 * 1000
毫秒),如果上述两个条件同时成立,则认为发生了时间回绕,将 rollover
设置为 true
1 2 3 4 5 6 7 8 9
| bool TimerManager::detectClockRollover(uint64_t now_ms) { bool rollover = false; if (now_ms < m_previouseTime && now_ms < (m_previouseTime - 60 * 60 * 1000)) { rollover = true; } m_previouseTime = now_ms; return rollover; }
|
listExpiredCb
- 获取当前执行器该时间需要执行的回调函数列表,如果是一次性的计时器,则从
set
中摘除,如果是循环计时器,则重新放回set
中
cbs
是传入传出参数1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43
| void TimerManager::listExpiredCb(std::vector<std::function<void()> >& cbs) { uint64_t now_ms = sylar::GetCurrentMS(); std::vector<Timer::ptr> expired; { RWMutexType::ReadLock lock(m_mutex); if (m_timers.empty()) { return; } } RWMutexType::WriteLock lock(m_mutex); if (m_timers.empty()) { return; } bool rollover = detectClockRollover(now_ms); if (!rollover && ((*m_timers.begin())->m_next > now_ms)) { return; } Timer::ptr now_timer(new Timer(now_ms)); auto it = rollover ? m_timers.end() : m_timers.lower_bound(now_timer); while (it != m_timers.end() && (*it)->m_next == now_ms) { ++it; } expired.insert(expired.begin(), m_timers.begin(), it); m_timers.erase(m_timers.begin(), it); cbs.reserve(expired.size());
for (auto& timer : expired) { cbs.push_back(timer->m_cb); if (timer->m_recurring) { timer->m_next = now_ms + timer->m_ms; m_timers.insert(timer); } else { timer->m_cb = nullptr; } } }
|
Author:
mxwu
Permalink:
https://mingxuanwu.com/2024/07/29/202407291329/
License:
Copyright (c) 2023 CC-BY-NC-4.0 LICENSE