1 定时器函数

muduo EventLoop有三个定时器函数:

  1. class EventLoop : noncopyable
  2. {
  3. /// Runs callback at 'time'.
  4. /// Safe to call from other threads.
  5. ///
  6. TimerId runAt(Timestamp time, TimerCallback cb);
  7. ///
  8. /// Runs callback after @c delay seconds.
  9. /// Safe to call from other threads.
  10. ///
  11. TimerId runAfter(double delay, TimerCallback cb);
  12. ///
  13. /// Runs callback every @c interval seconds.
  14. /// Safe to call from other threads.
  15. ///
  16. TimerId runEvery(double interval, TimerCallback cb);
  17. ///
  18. /// Cancels the timer.
  19. /// Safe to call from other threads.
  20. ///
  21. void cancel(TimerId timerId);
  22. };

回调函数在EventLoop对象所属的线程发生,与onMessage()、onConnection()等网络事件函数在同一个线程。muduo的TimerQueue采用了平衡二叉树来管理未到期的timers,因此这些操作的事件复杂度是O(logN) 。

2 核心代码解读

TimerQueue采用timerfd_create创建一个timer的描述符,通过epoll复用函数和其他socket描述符一样被监听
当timer超时时,会触发epoll监听到可读事件,TimerQueue就可以在epoll返回后触发回调函数,执行超时之后的任务(TimerQueue内部有个timer list,可以在超时后执行多个任务,因为可能多个timer同时超时)。
需要注意的时,增删timer是在EventLoop IO监听线程,防止出现多线程同时修改的同步问题。

2.1 创建timer描述符并监听

  1. TimerQueue::TimerQueue(EventLoop *loop)
  2. : loop_(loop),
  3. timerfd_(createTimerfd()), //创建timer描述符
  4. timerfdChannel_(loop, timerfd_), //根据timer描述符创建channel
  5. timers_(),
  6. callingExpiredTimers_(false)
  7. {
  8. //设置channel的可读回调,即timer超时回调函数
  9. timerfdChannel_.setReadCallback(std::bind(&TimerQueue::handleRead, this));
  10. // we are always reading the timerfd, we disarm it with timerfd_settime.
  11. timerfdChannel_.enableReading(); //加入epoll wiat list
  12. }
  13. void TimerQueue::handleRead()
  14. {
  15. loop_->assertInLoopThread();
  16. Timestamp now(Timestamp::now());
  17. readTimerfd(timerfd_, now); //timer描述符的可读事件,需要read一下
  18. std::vector<Entry> expired = getExpired(now); //查找timer list并删除超时的timer
  19. callingExpiredTimers_ = true;
  20. cancelingTimers_.clear();
  21. // safe to callback outside critical section
  22. for (const Entry &it : expired)
  23. {
  24. it.second->run(); //调用timer对象的超时回调函数
  25. }
  26. callingExpiredTimers_ = false;
  27. reset(expired, now);
  28. }

2.2 增删timer

以下两个函数是在IO线程执行,加入到EventLoop的pending factors中,等待loop循环中执行,避免了线程同步问题。

  1. void TimerQueue::addTimerInLoop(Timer *timer)
  2. {
  3. loop_->assertInLoopThread();
  4. bool earliestChanged = insert(timer);
  5. if (earliestChanged)
  6. {
  7. resetTimerfd(timerfd_, timer->expiration()); //设置timer描述符的超时时间
  8. }
  9. }
  10. void TimerQueue::cancelInLoop(TimerId timerId)
  11. {
  12. loop_->assertInLoopThread();
  13. assert(timers_.size() == activeTimers_.size());
  14. ActiveTimer timer(timerId.timer_, timerId.sequence_);
  15. ActiveTimerSet::iterator it = activeTimers_.find(timer); //在timer list中查找要取消的timer
  16. if (it != activeTimers_.end())
  17. { //删除此timer,这样timer描述符可读事件来了,会被丢掉不处理
  18. size_t n = timers_.erase(Entry(it->first->expiration(), it->first));
  19. assert(n == 1);
  20. (void)n;
  21. delete it->first; // FIXME: no delete please,删除timer对象
  22. activeTimers_.erase(it);
  23. }
  24. else if (callingExpiredTimers_)
  25. {
  26. cancelingTimers_.insert(timer);
  27. }
  28. assert(timers_.size() == activeTimers_.size());
  29. }