博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
muduo 源码分析底层IO类
阅读量:3942 次
发布时间:2019-05-24

本文共 4738 字,大约阅读时间需要 15 分钟。

文章目录

muduo 底层IO类底层通过poll 和 epoll 来实现的,通过一个抽象类Poller 提供接口,PollPoller 和 EPollPoller来继承Poller 类

Poller

//监听事件的函数,返回一个事件就绪的事件  virtual Timestamp poll(int timeoutMs, ChannelList* activeChannels) = 0;  /// Changes the interested I/O events.  /// Must be called in the loop thread.  //实现为纯虚函数,在PollPoller或EPollPoller 中实现  //更新所监听的事件  virtual void updateChannel(Channel* channel) = 0;  /// Remove the channel, when it destructs.  /// Must be called in the loop thread.  //删除一个Channel   virtual void removeChannel(Channel* channel) = 0;

PollPoller

typedef std::vector
PollFdList; PollFdList pollfds_; //struct pollfd 的数组,存放所有监听的文件描述符以及事件

poll

Timestamp PollPoller::poll(int timeoutMs, ChannelList* activeChannels){
// XXX pollfds_ shouldn't change //待处理事件的数量,在此处监听 int numEvents = ::poll(&*pollfds_.begin(), pollfds_.size(), timeoutMs); int savedErrno = errno; //记录事件产生的事件,便于下次定时器的跟新 Timestamp now(Timestamp::now()); //有就绪事件产生 if (numEvents > 0) {
LOG_TRACE << numEvents << " events happened"; //将所有有事件发生的文件描述符所对应的Channle 放到activeChannels中 fillActiveChannels(numEvents, activeChannels); } //事件超时 else if (numEvents == 0) {
LOG_TRACE << " nothing happened"; } //产生错误 else {
if (savedErrno != EINTR) {
errno = savedErrno; LOG_SYSERR << "PollPoller::poll()"; } } return now;}

fillActiveChannels

void PollPoller::fillActiveChannels(int numEvents,                                    ChannelList* activeChannels) const{
//依次取出就绪的事件的channel for (PollFdList::const_iterator pfd = pollfds_.begin(); pfd != pollfds_.end() && numEvents > 0; ++pfd) {
//如果当前的channel 上有事件产生 if (pfd->revents > 0) {
--numEvents; ChannelMap::const_iterator ch = channels_.find(pfd->fd); assert(ch != channels_.end()); Channel* channel = ch->second; assert(channel->fd() == pfd->fd); //设置该文件描述符上的事件 //该函数不做处理,只设置到达的事件 channel->set_revents(pfd->revents); // pfd->revents = 0; activeChannels->push_back(channel); } }}

updateChannel

void PollPoller::updateChannel(Channel* channel){
Poller::assertInLoopThread(); //记录日志 LOG_TRACE << "fd = " << channel->fd() << " events = " << channel->events(); //如果channel->index() < 0 表示新添加一个Channel if (channel->index() < 0) {
// a new one, add to pollfds_ assert(channels_.find(channel->fd()) == channels_.end()); struct pollfd pfd; //非阻塞IO 注册 pfd.fd = channel->fd(); //新产生的文件描述符 pfd.events = static_cast
(channel->events()); pfd.revents = 0; //每次循环监听都会从pollfds_中读取需要监听的文件描述符, //所以添加到pollfds_之后下次循环就会监听 pollfds_.push_back(pfd); int idx = static_cast
(pollfds_.size())-1; channel->set_index(idx); //用于管理所有的Channel 对象 channels_[pfd.fd] = channel; } //表示该Channel 已经存在,更新监听的事件 else {
// update existing one assert(channels_.find(channel->fd()) != channels_.end()); assert(channels_[channel->fd()] == channel); int idx = channel->index(); assert(0 <= idx && idx < static_cast
(pollfds_.size())); struct pollfd& pfd = pollfds_[idx]; assert(pfd.fd == channel->fd() || pfd.fd == -channel->fd()-1); //更新已经存在的Channel pfd.fd = channel->fd(); pfd.events = static_cast
(channel->events()); pfd.revents = 0; if (channel->isNoneEvent()) {
// ignore this pollfd pfd.fd = -channel->fd()-1; } }}

remove

void PollPoller::removeChannel(Channel* channel){
Poller::assertInLoopThread(); LOG_TRACE << "fd = " << channel->fd(); //断言当前的Channel 已经存在 assert(channels_.find(channel->fd()) != channels_.end()); //断言channels_ 存在的Channel 与 要删除的Channel 一致 assert(channels_[channel->fd()] == channel); //断言当前的channel 没有要监听的事件 assert(channel->isNoneEvent()); int idx = channel->index(); assert(0 <= idx && idx < static_cast
(pollfds_.size())); const struct pollfd& pfd = pollfds_[idx]; (void)pfd; assert(pfd.fd == -channel->fd()-1 && pfd.events == channel->events()); //删除一个Channel size_t n = channels_.erase(channel->fd()); assert(n == 1); (void)n; if (implicit_cast
(idx) == pollfds_.size()-1) {
pollfds_.pop_back(); } else {
int channelAtEnd = pollfds_.back().fd; //idx 文件描述符在vector中的位置 //将最后一个文件描述符与要删除的为文件描述符交换, //消除了删除一个元素的数据移动带来的开销 iter_swap(pollfds_.begin()+idx, pollfds_.end()-1); if (channelAtEnd < 0) {
channelAtEnd = -channelAtEnd-1; } //重新设置最后一个文件描述符的index channels_[channelAtEnd]->set_index(idx); //删除一个文件描述符 pollfds_.pop_back(); }}

EPollPoller

typedef std::vector
EventList; int epollfd_; //epoll下用于监听其他文件描述符的文件描述符 EventList events_; //监听的事件列表

关于EpollPoller 的 poll 、updateChannel 、removeChannel ,功能与PollPoller 的一样,实现的内部函数不同,这里不作介绍。

转载地址:http://ianwi.baihongyu.com/

你可能感兴趣的文章
在VMware Workstation中批量创建上千台虚拟机
查看>>
linux常用软件收集
查看>>
linux查看桌面环境
查看>>
centos8安装ntfs-3g后,不能自动挂载U盘(NTFS格式)
查看>>
Linux安装显卡驱动
查看>>
使用minicom
查看>>
linux常用外设-打印机指纹和蓝牙的安装管理
查看>>
记录一下安装在移动硬盘上的fedora linux v33在各种笔记本下的兼容性
查看>>
关于安装系统后不能启动的问题!
查看>>
U盘的挂载过程-先记录一下
查看>>
python程序启动过程报错的排错一般步骤
查看>>
linux下UEFI的管理
查看>>
类thinkpad笔记本安装deepinv20后启动黒屏的解决
查看>>
利用本地centos镜像升级centOS
查看>>
FreeBSD常用操作
查看>>
VC及esxi升级的必要性和步骤
查看>>
hp DL338服务器修改ilo管理地址
查看>>
vmware convert P2V 错误二三事
查看>>
让kali2020中的zsh有补完功能
查看>>
python解开压缩文件6位纯数字密码
查看>>