muduo Reactor結構分析

     muduo採用的是one Loop per Thread 的模式,即每個線程中有一個主循環,再配合着IO多路複用,即可實現在一個線程中同時監聽多個fd。主要利用EventLoop{.h/.cc} Channel{.h/.cc} Epoll{.h/.cc}來實現Reactor模式。

回顧Reactor事件處理模式

    Reactor模式是瞭解高性能IO的最基礎模式,其主要的思想是,將需要處理的IO事件註冊到一個IO多路複用的fd上,讓單線程/單進程來監聽這個fd,如果fd上監聽的事件被觸發則立刻調用不同事件的處理器(回調函數)進行處理。

     在c++11中,可以簡單使用function/bind來實現回調關係,使得編碼更加簡潔。

EventLoop類具體分析

class EventLoop{
public:
    EventLoop();
    ~EventLoop();
    void loop();
    void assertInLoopThread(){
        if(!isInLoopThread()){
            abortNotInLoopThread();
        }
    }
    EventLoop* getEventLoopOfCurrentThread();
    bool isInLoopThread() const { return threadId_ ==static_cast<pid_t>(pthread_self());}
    
    void updateChannel(Channel* channel);
    void removeChannel(Channel* channel);
    void quit();
private:
    typedef std::vector<Channel*> ChannelList;
    void abortNotInLoopThread();
    bool loop_;
    const pid_t threadId_;
    std::unique_ptr<Epoll> poller_;
    bool quit_;
    ChannelList activeChannels_;
};

    EventLoop中最重要的loop函數,裏面有一個循環調用poller->poll(),每次都將activesChannels_傳入poll函數來獲得在本次循環中觸發事件的channel,然後更具事件的不同種類(新連接,可讀,可寫)來分別調用不同的觸發器。

void EventLoop::loop(){
    ...
    while (!quit_)//one loop per thread指的就是這個loop
    {
        activeChannels_.clear();
        //pollreturntime = poller_->poll(kPollTimes,&activeChannels_);//這裏調用poll看有無發生事件,如果有則放到了activechannels_
        poller_->poll(kPollTimes,&activeChannels_);//先不用Timestamp
        for(ChannelList::iterator it=activeChannels_.begin();it!=activeChannels_.end();++it){
            (*it)->handleEvent();//進行處理事件
        }
    }
    ...
}

Channel類具體分析

    Channel類其實是fd的一個抽象,即每個Channel對應一個fd及對其操作。

class Channel : noncopyable{
public:
    typedef function<void()> EventCallback;
    Channel(EventLoop* loop,int fd);
    void handleEvent(); //根據revents的值調用不同的用戶調用
    void setReadCallback(const EventCallback& cb){
        readcallback_=cb;
    }
    void setWriteCallback(const EventCallback& cb){
        writecallback_=cb;
    }
    void setErrorCallback(const EventCallback& cb){
        errorcallback_=cb;
    }

    int fd() const{ return fd_; }
    int events() const { return events_; }
    void set_revents(int revt) { revents_=revt; }
    bool isNoneEvent() const { return events_ == kNoneEvent; }

    void enableReading() {events_ |= kReadEvent; update(); }
    void enableWriting() {events_ |= kWriteEvent; update(); }
    void disableWriting() {events_ &= ~kWriteEvent; update(); }
    void diableAll() {events_ = kNoneEvent; update(); }

    int index() const { return index_; }
    void set_index(int index) { index_ = index; }

    EventLoop* ownerLoop() const { return loop_; }
private:
    void update();//用於更改完events後的更新操作

    static const int kNoneEvent;
    static const int kReadEvent;
    static const int kWriteEvent;

    EventLoop* loop_;//每個channel對應一個EventLoop
    const int fd_;//每個channel對應一個fd
    int events_; //fd關心的io事件
    int revents_;//目前活動的事件
    int index_; //kAdded(已經監聽),kNew(新建),kDeleted(已經被刪除),用於體現當前fd的狀態

    EventCallback readcallback_;
    EventCallback writecallback_;
    EventCallback errorcallback_;
};

    當事件分發器分發好不同的觸發事件種類後,就要調用Channel::handleEvent()來處理。readcallback_,writecallback_,errorcallback_都是之前通過setReadCallback(),setWriteCallback(),setErrorCallback()註冊過的,這裏即可體現出Reactor事件處理模式的核心思想。

void Channel::handleEvent(){
    if(revents_ & EPOLLERR) {
       if(errorcallback_) errorcallback_();
    }
    if(revents_ & (EPOLLIN | EPOLLPRI | EPOLLRDHUP)){
        if(readcallback_) readcallback_();
    }
    if(revents_ & EPOLLOUT){
        if(writecallback_) writecallback_();
    }
}

Epoll類具體分析

class Epoll : noncopyable{
public:
    typedef std::vector<Channel*> ChannelList;
    Epoll(EventLoop* loop);
    ~Epoll();
    void poll(int timeoutMs,ChannelList* activeChannel);//先不返回Timestamp
    void updateChannel(Channel* channel);
    void removeChannel(Channel* channel);
    void assertInLoopThread() { ownerLoop_->assertInLoopThread(); }
private:
    static const int kInitEventsize = 20;
    void fillActiveChannels(int numEvents,ChannelList* activeChannels) const;
    void update(int operation, Channel* channel);
    typedef std::vector<struct epoll_event> EventList;
    typedef std::map<int,Channel*> ChannelMap;
    EventLoop* ownerLoop_;
    int epollfd_;
    EventList events_;//vector<epoll_event>監聽的事件
    ChannelMap channels_;//map<fd,fd所對應的channel*>
};

    Epoll類是對epoll處理的抽象類,正確的epoll使用方法是epoll_create -> epoll_ctl -> epoll_wait,分別在Epoll::Epoll(),Epoll::update(),Epoll::poll()中進行處理,這裏對於epoll的原理不再概述。

參考:muduo源碼,Linux多線程服務器編程

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章