1. 程式人生 > 實用技巧 >muduo原始碼解析23-網路庫1:eventloop初步瞭解

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