目录
1、概述
Poller中有很多纯虚函数,是一个抽象类,不能实例化
为什么muduo库要抽象一层Poller?
因为在Eventloop里面,在使用I/O复用的时候,并没有直接指定epoll,因为muduo库本身对外提供I/O复用的能力有2个:1个是poll,1个是epoll,在Eventloop里面,不可能直接去使用poll或者epoll。是从抽象层面直接使用抽象类poller,到时候引用不同的派生类对象,调用它们的同名覆盖方法,就可以非常方便地去扩展不同的I/O复用能力,就是多路分发器。
poller监听的就是Eventloop保存的那些channel
protected的成员变量就是让派生类可以访问到,private的成员变量派生类不能访问到。
2、重写Poller.h
#include "noncopyable.h"
#include "Timestamp.h"
#include <vector>
#include <unordered_map>
class Channel;//只用到指针类型
class EventLoop;
//muduo库中多路事件分发器的核心IO复用模块
class Poller:noncopyable
{
public:
using ChannelList=std::vector<Channel*>;
Poller(EventLoop* loop);
virtual ~Poller()=default;
//给所有IO复用保留统一的接口
virtual Timestamp poll(int timeoutMs,ChannelList* activeChannels)=0;//相当于启动了epoll_wait,activeChannels:当前被激活的channel(需要被poller照顾的channel)
virtual void updateChannel(Channel* channel)=0;//相当于epoll_ctl
virtual void removeChannel(Channel* channel)=0;//相当于通过epoll_ctl将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
};
3、重写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;
}
4、newDefaultPoller.cc
为什么不把 newDefaultPoller写在Poller.cc?
如果真的把newDefaultPoller写在Poller.cc里面,从语法上来说,没有错误。
但是这个函数是要生成一个具体的I/O复用对象,并返回一个基类的指针。
所以就得用下面这2个头文件,才能去生成一个具体的实例对象并返回回去,这样不合理,因为继承结构中,poller是基类,只能派生类引用基类,基类不能引用派生类
那这个newDefaultPoller实现在哪呢?
muduo默认使用epoll
getenv()用于获取环境变量
DefaultPoller.cc包含具体实现类的头文件PollPoller.h和EPollPolar.h就没有问题,因为DefaultPoller.cc属于跟Pollar相关的一个公共的源文件,添加依赖关系是没有关系的,但是Poller是基类属于最上层,派生类可以引用它,但是它最好不要引用派生类的相关资源,因为基类本身就是一个抽象的概念,不能依赖具体的实现
#include "Poller.h"
#include <stdlib.h>
Poller* Poller::newDefaultPoller(EventLoop* loop)
{
if(::getenv("MUDUO_USE_POLL"))
{
return nullptr;//生成poll的实例
}
else
{
return nullptr;//生成epoll的实例
}
}