重写muduo之Poller抽象层

发布于:2024-05-06 ⋅ 阅读:(28) ⋅ 点赞:(0)

目录

1、概述

2、重写Poller.h

3、重写Poller.cc

4、newDefaultPoller.cc


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的实例
    }
}