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