muduo--Reactor的关键构成

2 篇文章 0 订阅
Reactor(muduo中主要涉及Eventloop,Poller,Channel)一个事件循环对应一个IO线程,IO线程执行EventLoop事件主循环,该主循环loop调用IO复用器poller监听事件集合,并将就绪事件通过事件分发器Channel执行相应的事件回调。

1、 Eventloop 事件循环:反应器( reactor ):负责 IO 和定时器事件的分派。
关键函数:
void EventLoop::loop():该函数的作用是调用poller_的poll()函数,在该函数中调用IO复用的系统调用,muduo库中是poll和epoll,然后调用activeChannels_中每一个Channel的回调函数(通过调用Channel中的handleEvent()函数调用相应回调函数)。通过poller_->poll()函数得到的activeChannels_全部是活动的Channel。

2、 Class Channel 事件分发器,主要用于事件注册和事件处理。 记录了描述符fd的注册事件和就绪事件以及就绪事件的回调函数;只属于一个Eventloop,每个channel对象自始至终只负责一个文件描述符fd的IO事件的分发,但它并不拥有这个fd,把不同的IO事件分发为不同的回调,如:ReadCallback和WriteCallback。
关键数据: intfd_负责的描述符;intevent_文件描述符的注册事件;int revents_文件描述符的就绪事件,以及事件回调ReadCallback等。
主要函数调用过程:当一个fd 想要注册事件并在事件就绪时执行相应的就
事件回调时:
Channel::update(this)->
EventLoop::updateChannel(Channel*)
Poller::updateChannel(Channel*)调用链向poll系统调用的侦听事件表注册或者修改注册事件。Poller修改Channel,若Channel已经存在于Poller的vector,则Poller调用Channel::events()获得事件并重置vector中的pollfd,若Channel没有在vector中则向Poller的vector添加新的文件描述符事件到事件表中,并将vector.size()作为Channel::set_index()作为channel记住自己在Poller中的位置。
Channel作为事件分发器其核心结构是Channel::handleEvent()该函数执行fd上就绪事件相应的回调。
void set_revents(int revt)->handleEvent():设定fd的就绪事件类型,在poll返回就绪事件后将就绪事件类型传给set_revents函数,然后此函数传给handlevent,handleEvent根据就绪事件的类型决定执行那个事件回调函数。
Channel::~Channel()->
EventLoop::removeChannel(Channel*)->
Poller::removeChannel(Channel*)
将Poller中的Channel*移除防止空悬指针。因为Channel的生命周期和Poller/EventLoop不一样长。

3、 class Poller 实现IO multiplexing ,其功能仅仅是poll系统调用的简单 封装,它并不拥有channel ,只是对channel*指针进行组织和监测(所以channel必须要自己解除注册,以防止有野指针)。
关键数据结构:
vectorpollfds_========事件结构体数组;
mapchannels_========用于文件描述符fd到Channel的映射便于快速查找到相应的Channel,如poll返回后遍历pollfds_找到就绪事件的fd再通过channels_找到fd的channel然后就可以通过Channel::handleEvent()执行就绪事件回调。
注:vector中存储的是channel->fd,而map中存储的是fd和channel。
关键函数调用:
Poller::poll(inttimeoutMs,vectoractiveChannels)(其中调用了PollPoller::fillActiveChannels):调用poll监听事件集合,并在timeout时间内就绪的事件集合通过activeChannels返回(EventLoop中loop()获得该集合后,调用Channels相应的回调函数)。这里Poller::poll()返回后本可以执行Channel::handleEvent()将就绪事件的回调执行了,但并没有这样做的原因:channel::handleEvent()可能修改Poller的两个容器,即添加或者删除,在遍历容器时会很危险的,同时为了简化Poller,Poller的职责就是IO复用,至于事件分发还是交给Channel自己完成。
muduo库只支持poll和epoll,所以定义Poller基类并提供PollPoller和EPollPoller两个类。在EventLoop的构造函数初始化列表中poller_(Poller::newDefaultPoller(this))。

这三个类是构成Reactor模式的核心内容,基本调用过程如下图:


  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值