從epoll構建muduo-6 加入EventLoop和Epoll

mini-muduo版本傳送門
version 0.00 從epoll構建muduo-1 mini-muduo介紹
version 0.01 從epoll構建muduo-2 最簡單的epoll
version 0.02 從epoll構建muduo-3 加入第一個類,順便介紹Reactor
version 0.03 從epoll構建muduo-4 加入Channel
version 0.04 從epoll構建muduo-5 加入Acceptor和TcpConnection
version 0.05 從epoll構建muduo-6 加入EventLoop和Epoll
version 0.06 從epoll構建muduo-7 加入IMuduoUser
version 0.07 從epoll構建muduo-8 加入發送緩衝區和接收緩衝區
version 0.08 從epoll構建muduo-9 加入onWriteComplate回調和Buffer
version 0.09 從epoll構建muduo-10 Timer定時器
version 0.11 從epoll構建muduo-11 單線程Reactor網絡模型成型
version 0.12 從epoll構建muduo-12 多線程代碼入場
version 0.13 從epoll構建muduo-13 Reactor + ThreadPool 成型

mini-muduo v0.05版本,完整可運行的示例可從github下載,使用命令git checkout v0.05可切換到此版本,在線瀏覽此版本到這裏 本版將程序的主要類都加入進來了,這個版本可以作爲一個里程碑版本,最重要的修改是加入了兩個類EventLoop和Epoll。加入這兩個類後,程序代碼邏輯就相對清晰多了。爲了有個更直觀的瞭解,我們對照之前介紹的最簡單epoll示例(從epoll構建muduo-2 最簡單的epoll),看看原始示例裏的關鍵代碼現在都跑哪去了。


1 先來看EventLoop,根據名字可以猜測這個類的作用是事件循環,其實這個類就是用來包裝for循環的,也就是那個套在epoll_wait外面的for循環,這個for循環可以說是整個程序最核心的部分,for循環等待在epoll_wait上,然後遍歷返回的每個事件,先通知到Channel,然後由Channel通知到最終的事件處理程序(位於Acceptor和TcpConnection中)。在上一個版本中。for循環位於TcpServer裏,現在我們把它移動到EventLoop的loop方法裏,用while代替for,作用跟之前的for循環一樣:等待在epoll_wait上,當有事件發生時,回調Channel。當然,EventLoop::loop()不是直接調用epoll_wait,而是使用了其包裝類Epoll。

2 Epoll類的作用是包裝epoll文件描述符,它最重要的成員變量是一個epoll文件描述符,最重要的兩個方法是poll和update。poll方法包裝了epoll_wait,在epoll描述符上等待事件的發生,當有事件發生後將新建的Channel填充到vector中,update方法包裝了epoll_ctl,用來在epoll文件描述符上添加/修改/刪除事件。update接收一個Channel作爲參數,通過這個Channel可以獲得要註冊的事件(Channel::getEvents()方法)。以後所有涉及epoll描述符的操作都通過Epoll的這兩個方法來完成。EventLoop本來是應該包括一個epoll描述符的,loop方法通過一個循環來調用epoll_wait,而現在epoll描述符在Epoll中,所以EventLoop只需要包含一個Epoll成員變量即可。EventLoop在循環中只需要調用Epoll::poll()方法就可以獲得Channel列表,不需要直接調用epoll_wait了。

3 Epoll和EventLoop應該是一一對應的關係,每個EventLoop有且只有一個Epoll。 在原始的muduo中,爲了兼顧epoll/poll編程,作者爲IO複用寫了公共父類Poller,這裏我進行了簡化,直接實現了一個epoll的包裝類Epoll而忽率了poll。

4 TcpServer也做了相應修改,在start方法裏沒有了epoll的創建過程,也沒有了for循環。epoll的創建過程移動到Epoll的構造函數裏。整個for循環都移動到EventLoop中,而真正啓動循環的位置從TcpServer裏移動到main函數裏。TcpServer的另一處修改是將成員變量_epollfd換成EventLoop,因爲EventLoop包含一個Epoll,而後者就是用來包裝epoll文件描述符的,所以這個修改也很容易理解。

5 以前傳遞epollfd的地方,改爲EventLoop* ,因爲EventLoop和Epoll是一一對應的關係,而Epoll又是epollfd的包裝,拿到EventLoop就等於拿到了epoll描述符。

6 Channel添加了方法getEvents()和getSockfd(),使Epoll可以通過Channel獲得必須的events和fd。

7 新增了一處內存泄漏new Epoll 後續處理。

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