讀Muduo原始碼筆記---8(定時器)
阿新 • • 發佈:2018-11-04
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_; // 儲存的是被取消的定時器 };