muduo原始碼解析23-網路庫1:eventloop初步瞭解
eventloop類:
作用:
我們在利用IO複用例如epoll構建伺服器的時候,最基本的做法:
epoll_create(); while(1) { epoll_wait(); handleEvent(); }
如果向上面那樣寫的話,隨著伺服器功能要求增多,那個迴圈體肯定越來越大,程式碼難以理解與維護。
因此使用eventloop對這個迴圈體本身進行一次封裝。
eventloop.h:
一開始的話eventloop類很簡單,需要注意的是我們要求一個執行緒只能有一個eventloop物件,啥意思呢,
之前我們用while(1){epoll_wait();...}時,也是一個執行緒只有一個while(1){...},
eventloop正是對其進行封裝,因此要求 one eventloop one thread
#ifndef EVENTLOOP_H #define EVENTLOOP_H #include<pthread.h> #include"base/noncopyable.h" namespace mymuduo { namespace net { class eventloop:noncopyable { public: eventloop(); ~eventloop(); //eventloop的核心函式,用於不斷迴圈,在其中呼叫poller::poll()用於獲取發生的網路事件void loop(); //斷言,eventloop所屬於的執行緒ID就是當前執行緒的ID void assertInLoopThread(); //判斷是否eventloop所屬於的執行緒ID就是當先執行緒的ID bool isInLoopThread() const; //獲得當前執行緒的那個eventloop* eventloop* getEventLoopOfCurrentThread(); private: //LOG_FATAL void abortNotInLoopThread(); bool m_looping; //eventloop是否正在loop const pid_t m_threadId; //eventloop所在的那個執行緒ID,要求one eventloop one thread }; }//namespace net }//namespace mymuduo #endif // EVENTLOOP_H
eventloop.cpp
#include "eventloop.h" #include"base/currentthread.h" #include"base/logging.h" #include<poll.h> namespace mymuduo { namespace net { //每個執行緒都有一個t_loopInThisThread,表示當前執行緒擁有的那個eventloop* __thread eventloop* t_loopInThisThread=0; //建構函式,初始化成員,設定當前執行緒的t_loopInThisThread為this eventloop::eventloop() :m_looping(false),m_threadId(currentthread::tid()) { LOG_TRACE<<"eventloop created "<<this<<" in thread "<<m_threadId; //判斷當前執行緒是否已經存在eventloop了,保證最多隻有一個 if(t_loopInThisThread) //多建立eventloop報錯 LOG_FATAL<<"another eventloop "<<this<<" exits in this thread "<<m_threadId; else t_loopInThisThread=this; } eventloop::~eventloop() { assert(!m_looping); t_loopInThisThread=NULL; //刪除當前執行緒的那個eventlloop*,指向NULL } void eventloop::loop() { assert(!m_looping); assertInLoopThread(); m_looping=true; ::poll(NULL,0,5*1000); //poll 5s 等待網路事件 LOG_TRACE<<"eventllop "<<this<<" stop looping"; m_looping=false; } //斷言,當前執行緒就是eventloop所在的執行緒 void eventloop::assertInLoopThread() { if(!isInLoopThread()) abortNotInLoopThread(); } //... bool eventloop::isInLoopThread() const { return m_threadId==currentthread::tid(); } //獲取當前執行緒的那個eventloop* eventloop* eventloop::getEventLoopOfCurrentThread() { return t_loopInThisThread; } //LOG_FATAL,錯誤:eventloop所屬執行緒不是當前執行緒 void eventloop::abortNotInLoopThread() { LOG_FATAL << "EventLoop::abortNotInLoopThread - EventLoop " << this << " was created in threadId_ = " << m_threadId << ", current thread id = " << currentthread::tid(); } }//namespace net }//namespace mymuduo
時序圖很簡單
eventloop物件建立-->
eventloop::loop()開始迴圈-->
{
(在loop()中執行如下操作)
::poll/::epoll_wait()等待網路事件發生
handleEvent()處理網路事件,(之後會提到)
}
和之前的
while(1)
{
epoll_wait();
handeEvent();
}
基本是一樣的。
需要注意的有兩點:
1.一個執行緒只能有一個eventloop
2.一個執行緒不能去呼叫另一個執行緒中的eventloop::loop()
測試:
#include "net/eventloop.h" #include"base/logging.h" #include"base/thread.h" #include <assert.h> #include <stdio.h> #include <unistd.h> using namespace mymuduo; using namespace mymuduo::net; //由於eventloop只能屬於一個執行緒,loop()只能夠在當前執行緒呼叫 //1.測試一下一個執行緒建立多個eventloop報錯 //2.測試一下別的執行緒呼叫當前執行緒的eventloop::loop()報錯 void test1() { eventloop loop1; eventloop loop2; //error,一個執行緒只允許有一個eventloop } eventloop* g_loop; void workerthread() { g_loop->loop(); //error,不能呼叫別的執行緒的eventloop::loop() } void test2() { eventloop loop; g_loop=&loop; mymuduo::thread t1(workerthread,"t1"); t1.start(); t1.join(); } int main() { mymuduo::logger::setLogLevel(mymuduo::logger::TRACE); test2(); }
列印結果:
test1:
2020年09月01日 星期2 15:16:52.1598944612 57327 TRACE eventloop eventloop created 0x7FFF3026AC80 in thread 57327 - eventloop.cpp:22
2020年09月01日 星期2 15:16:52.1598944612 57327 TRACE eventloop eventloop created 0x7FFF3026AC90 in thread 57327 - eventloop.cpp:22
2020年09月01日 星期2 15:16:52.1598944612 57327 FATAL another eventloop 0x7FFF3026AC90 exits in this thread 57327 - eventloop.cpp:25
test2:
2020年09月01日 星期2 15:17:24.1598944644 57525 TRACE eventloop eventloop created 0x7FFF0BBBA640 in thread 57525 - eventloop.cpp:22
2020年09月01日 星期2 15:17:24.1598944644 57546 FATAL EventLoop::abortNotInLoopThread - EventLoop 0x7FFF0BBBA640 was created in threadId_ = 57525, current thread id = 57546 - eventloop.cpp:67