先简单说一下,因为我参考的是flamingo的代码,会和muduo有一点点出入,但是基本是差不多,因为前者是基于后者开发的,可能有一点点改动。
EventLoop是muduo里比较核心的类吧,因为它是实现Reactor模式的核心,什么是Reactor模式,其实很多文章和书籍都有讲,我也打算抽空写一篇博客,来总结下自己的心得,至少现在没有总结,哈哈~~。
其实如果认真读一下EventLoop里的Loop循环的话,就可以很好的了解Reactor模式了,
不过还是先从成员开始吧!
成员
private:
typedef std::vector<Channel*> ChannelList;
bool looping_; /* atomic */
bool quit_; /* atomic and shared between threads, okay on x86, I guess. */
bool eventHandling_; /* atomic */
bool callingPendingFunctors_; /* atomic */
const std::thread::id threadId_;//对应的线程id号
Timestamp pollReturnTime_;
std::shared_ptr<Poller> poller_;//初始化默认创建EpollPoller
std::shared_ptr<TimerQueue> timerQueue_;
int64_t iteration_;
SOCKET wakeupFd_; //TODO: 这个fd什么时候释放?,在EventLoop被析构的时候会释放,但是确实没有找到相应调用析构的代码。
// unlike in TimerQueue, which is an internal class,
// we don't expose Channel to client.
std::shared_ptr<Channel> wakeupChannel_;
// scratch variables
ChannelList activeChannels_;//epoll事件会被压入这个vector
Channel* currentActiveChannel_;//被用来遍历,上一行的vector
std::mutex mutex_;//用来保护下面那行的执行
std::vector<Functor> pendingFunctors_; // Guarded by mutex_
Functor frameFunctor_;
};
注意!为了减少行数,我把#indef win32给删掉了。
先简单说一下4个bool型的变量:
looping_代表是否开始循环。
quit_代表是否退出。
eventHandling_代表是否在处理事件。
callingPendingFunctors_代表是否在处理被push的待执行函数(此处后面会说一下)。
说一下这个东西
SOCKET wakeupFd_;//TODO: 这个fd什么时候释放?,在EventLoop被析构的时候会释放,但是确实没有找到相应调用析构的代码。
这个socket使用来唤醒的,有一个wakeup函数,会向这个socket写入一个uint64_t one = 1;来唤醒它。不过这个释放,确实没有找到具体的实现位置,它会在EventLoop被析构的时候被释放,但是muduo代码里好像没有析构EventLoop的代码,而且EventLoopThread和EventLoopThreadPool持有EventLoop的方式是使用EventLoop*,也不是使用智能指针,不会自动清理,其实算是一个会造成内存泄漏的问题点吧。不过muduo框架也没有重复的去创建EventLoop的过程,而是在程序一开始运行就初始化好了,所以也不会造成别的问题吧,只要客户代码不反复的去创建TcpServer,那就不会出现问题,所以这是需要注意的一点!在flamingo里面,chatServer,你可以就把它当作是TcpServer,是使用单例模式创建的,所以就避免了这个问题。
后续做一个小测试,反复创建看看效果如何!
后面也没有特别需要解释说明的成员了,基本在注释里就写好了。
构造
我们来看看它的构造
EventLoop::EventLoop()
: looping_(false),
quit_(false),
eventHandling_(false