为什么muduo库要抽象一层poller?因为在EventLoop里面,它在使用IO复用并没有说直接指定epoll,因为muduo库对外提供的IO复用的能力包含两个:poll和epoll,在EventLoop里面不可能直接使用poll或者epoll它是从抽象层面直接使用poller,到时候引用不同的派生类对象,调用它们的同名覆盖方法,就可以非常方便的去扩展不同的IO复用能力,就是多路分发器。
poller监听的就是eventloop保存的那些channel
protected的成员变量就是让派生类可以访问到,private的成员变量派生类不能访问到。
Poller.h
#pragma once
#include "noncopyable.h"
#include "Timestamp.h"
#include<vector>
#include<unordered_map>
//只用到指针类型
class Channel;
class EventLoop;
//muduo库中多路事件分发器的核心IO复用模块
class Poller{
public:
using ChannelList = std::vector<Channel*>;
Poller(EventLoop *loop);
virtual ~Poller();
//给所有IO复用保留统一的接口
virtual Timestamp poll(int timeoutMs, ChannelList *activeChannels) = 0;//相当于启动了epoll_wait
virtual void updateChannel(Channel* channel) = 0;//相当于启动了epoll_ctrl
virtual void removeChannel(Channel* channel) = 0;//fd所感兴趣的事件delete掉
//判断当前Channel是否在Poller当中
bool hasChannel(Channel *channel) const;
//EventLoop可以通过该接口获取默认的IO复用的具体实现
static Poller* newDefaultPoller(EventLoop *loop);
protected:
//map的key:sockfd value:sockfd所属的channel通道类型
using ChannelMap = std::unordered_map<int,Channel*>;
ChannelMap channels_;
private:
EventLoop *ownerLoop_; // 定义Poller所属的事件循环EventLoop
};
Poller.cc
#include "Poller.h"
#include "Channel.h"
Poller::Poller(EventLoop *loop)
:ownerLoop_(loop)
{
}
bool Poller::hasChannel(Channel *channel) const{
auto it = channels_.find(channel->fd());
return it != channels_.end() && it->second == channel;
}
为什么不把 newDefaultPoller写在Poller.cc? 如果真的把newDefaultPoller写在Poller.cc里面,从语法上来说,没有错误。 但是这个函数是要生成一个具体的I/O复用对象,并返回一个基类的指针。 所以就得用下面这2个头文件,才能去生成一个具体的实例对象并返回回去,这样不合理,因为继承结构中,poller是基类,只能派生类引用基类,基类不能引用派生类
那这个newDefaultPoller实现在哪呢?
muduo默认使用epoll
根据键返回对应的值
DefaultPoller.cc分解了poller和具体的epollpoller的强耦合
#include "Poller.h"
#include<stdlib.h>
Poller* Poller::newDefaultPoller(EventLoop *loop){
if(::getenv("MUDUO_USE_POLL")){
return nullptr; //生成poll的实例
}
else{
return new EPollPoller(loop); //生成epoll实例
}
}