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) {
// 设置timer的回调函数为空, 并且从队列中删除该timer
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; // 是否触发onTimerInsertedAtFront
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;
// set为空返回0
if (m_timers.empty()) {
return ~0ull;
}
// 否则返回set首个对象执行的时间差
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; // 用于传出
    // set为空 结束
    {
    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;
    }
    // 找到需要执行的计时器,将其从set移除,并加入到expired中,最后将回调函数放入cbs
    Timer::ptr now_timer(new Timer(now_ms));
    // 如果发生时间回绕, 则it为最后一项,否则it为比当前时间大的第一项
    auto it = rollover ? m_timers.end() : m_timers.lower_bound(now_timer);
    while (it != m_timers.end() && (*it)->m_next == now_ms) {
    ++it;
    }
    // 将begin()到it的部分插入到expired, 并从m_timers删除
    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;
    }
    }
    }