1. 程式人生 > >讀Muduo原始碼筆記---8(定時器)

讀Muduo原始碼筆記---8(定時器)

muduo的定時器由三個類實現,TimerId、Timer、TimerQueue。

1、採用timer_create函式得到定時器物件

      timerfd_create把時間變成了一個檔案描述符,該“檔案”在定時器超時的那一刻變得可讀,這樣就能很方便的融入到select/poll框架中,用統一的方式來處理I/O和超時事件,這正是Reactor模式的長處。

2、Timer類

     Timer是對定時器的高層次抽象,封裝了定時器的一些引數,例如超時回撥函式、超時時間、超時時間間隔、定時器是否重複、定時器的序列號。其函式大都是設定這些引數,run()用來呼叫回撥函式,restart()用來重啟定時器(如果設定為重複)。

class Timer : boost::noncopyable
{
 public:
  void run() const  //run函式來呼叫回撥函式
  {
    callback_();
  }

  Timestamp expiration() const  { return expiration_; }
  bool repeat() const { return repeat_; }
  int64_t sequence() const { return sequence_; }

  void restart(Timestamp now);

  static int64_t numCreated() { return s_numCreated_.get(); }

 private:
  const TimerCallback callback_;//超時回撥函式
  Timestamp expiration_;        //超時時間
  const double interval_;       //超時時間間隔
  const bool repeat_;           //定時器是否重複
  const int64_t sequence_;      //定時器的序列號

  static AtomicInt64 s_numCreated_;
};

//重複定時
void Timer::restart(Timestamp now)
{
  if (repeat_)//定時器是否重複
  {
    expiration_ = addTime(now, interval_);//計算超時時間
  }
  else
  {
    expiration_ = Timestamp::invalid();//return Timestamp()獲取一個無效時間
  }
}

3、TimerQueue

    TimerQueue的介面很簡單,只有兩個函式addTimer()和cancel()。它的內部有channel,和timerfd相關聯。新增新的Timer後,在超時後,timerfd可讀,會處理channel事件,之後呼叫Timer的回撥函式;在timerfd的事件處理後,還有檢查一遍超時定時器,如果其屬性為重複還有再次新增到定時器集合中。

class TimerQueue : boost::noncopyable
{
 public:
  TimerQueue(EventLoop* loop);
  ~TimerQueue();
 
  ///
  /// Schedules the callback to be run at given time,
  /// repeats if @c interval > 0.0.
  ///
  /// Must be thread safe. Usually be called from other threads.
  // 一定是執行緒安全的,可以跨執行緒呼叫。通常情況下被其它執行緒呼叫。
  TimerId addTimer(const TimerCallback& cb,
                   Timestamp when,
                   double interval);
 
  void cancel(TimerId timerId);
 
 private:
 
  // FIXME: use unique_ptr<Timer> instead of raw pointers.
  // unique_ptr是C++ 11標準的一個獨享所有權的智慧指標
  // 無法得到指向同一物件的兩個unique_ptr指標
  // 但可以進行移動構造與移動賦值操作,即所有權可以移動到另一個物件(而非拷貝構造)
  typedef std::pair<Timestamp, Timer*> Entry;
  typedef std::set<Entry> TimerList;
  typedef std::pair<Timer*, int64_t> ActiveTimer;
  typedef std::set<ActiveTimer> ActiveTimerSet;
 
  // 以下成員函式只可能在其所屬的I/O執行緒中呼叫,因而不必加鎖。
  // 伺服器效能殺手之一是鎖競爭,所以要儘可能少用鎖
  void addTimerInLoop(Timer* timer);
  void cancelInLoop(TimerId timerId);
  // called when timerfd alarms
  void handleRead();
  // move out all expired timers
  // 返回超時的定時器列表
  std::vector<Entry> getExpired(Timestamp now);
  void reset(const std::vector<Entry>& expired, Timestamp now);
 
  bool insert(Timer* timer);
 
  EventLoop* loop_;		// 所屬EventLoop
  const int timerfd_;
  Channel timerfdChannel_;
  // Timer list sorted by expiration
  TimerList timers_;	// timers_是按到期時間排序
 
  // for cancel()
  // timers_與activeTimers_儲存的是相同的資料
  // timers_是按到期時間排序,activeTimers_是按物件地址排序
  ActiveTimerSet activeTimers_;
  bool callingExpiredTimers_; /* atomic */
  ActiveTimerSet cancelingTimers_;	// 儲存的是被取消的定時器
};