day06-Poller
Poller 是对 Linux IO 多路复用(epoll)的封装抽象类。1 个 Poller 管理 多个 Channel,事件来了由 Poller 通知 Channel 处理,Poller = 监工,负责监听所有 fd 的事件(底层是 epoll)
poller 是抽象基类,不能实例化,定义统一接口:poll、update、remove,子类 EPollPoller 真正实现 epoll 操作。
Poller.h
1 |
|
1 | class Poller : noncopyable |
该Poller属于哪个EventLoop。
1 | protected: |
channels_:保存所有被监听的channel,通过fd找到对应的channelprotected权限,使子类(EpollPoller)可以调用。用
unordered_map不用map,因为在不要求有序,不要求遍历排序(map提供有序功能),unordered_map性能更高。
1 | Poller(EventLoop* loop); |
virtual 虚析构:多态安全,保证子类析构被执行,在子类析构中释放对应资源,防止资源泄漏。
1 | Poller* poller = new EpollPoller(loop); |
后续会像如上用父类指针指向子类对象
- 如果析构不是
virtual那么delete poller时:- 编译器看到的是 Poller* 指针
- 它只会调用 Poller 的析构函数
- 完全不会调用 EpollPoller 的析构函数。
- 加
virtual后再执行delete poller时:- 因为是 虚函数,编译器不会直接调用 Poller 的析构
- 它去查虚表,找到真实对象(EpollPoller)的析构
- 先调用 子类析构~EpollPoller ()
- 再自动调用 父类析构~Poller ()
1 | using ChannelList = std::vector<Channel*>; |
三个纯虚函数,是
poller全部功能,在子类中实现。poll底层对应epoll_wait, 把有事件的 Channel 填进传入的ChannelList里。updateChannel中的删除(DEL)只是临时取消监听,但 Channel 还在 Poller 里,只是从 epoll 中移除监听,channels_ 这个 map 里还保留着 channel。removeChannel中的删除是彻底从 Poller 中剥离 Channel,从 epoll 里删掉,从 channels_ map 里也删掉。
1 | bool hasChannel(Channel* channel) const; |
判断 Channel 是否被当前 Poller 管理
1 | static Poller* newDefaultPoller(EventLoop* loop); |
静态工厂方法,创建并返回一个 Poller 的具体实现(如 EpollPoller)
返回基类指针
实际指向子类对象(EpollPoller)
这就是 多态
Poller.cc
1 |
|
构造函数,成员初始化。
1 | bool Poller::hasChannel(Channel* channel) const |
channel->fd()拿到这个 Channel 对应的文件描述符。find(...)在 map 里查找这个 fd。- 双重安全判断
it != channels_.end()→ fd 在 map 里存在。it->second == channel→map 里存的 Channel 指针 == 传进来的这个 Channel。
为什么要判断两个条件?
因为 fd 会被系统重复利用!
例子:
- 旧 Channel(fd=5)关闭
- 系统把 fd=5 又分配给新 Channel
- 这时候
find(5)能找到,但对应的已经不是原来的 Channel
DefualtPoller.cc
1 |
|
新建DefaultPoller.cc文件,在这个文件里实现Poller中的newDefaultPoller函数。
这是简单工厂模式
- EventLoop 只知道 Poller,不知道 EpollPoller
- 解耦,以后想换 IO 模型,只改这里,不用动 EventLoop
为什么 newDefaultPoller 非要单独写一个文件?
Poller 是抽象接口,它不应该、也不能知道有
EpollPoller这个子类。newDefaultPoller () 必须知道 EpollPoller,因为它要
new EpollPoller。这两个需求冲突,所以必须分开文件
源码地址:
Poller.h:https://gitee.com/lpzdinghai/lpzmuduo/blob/master/Poller.h
DefaultPoller.cc:https://gitee.com/lpzdinghai/lpzmuduo/blob/master/DefaultPoller.cc