Muduo网络库的实现Poller class(三)

Muduo网络库的Poller类是IO复用的封装,不负责事件分发。核心功能是`poll()`,用于获取活跃IO事件并填充到activeChannels。`updateChannel()`则维护和更新pollfds_数组,当Channel不再关心事件时,通过设置pollfd.fd为-1使其被忽略。代码中展示了Poller.cc和Poller.h的关键部分。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

源码下载以及安装点击链接https://blog.youkuaiyun.com/YoungSusie/article/details/90021742

分类 Muduo网络库编程 学习笔记

Poller class是IO multiplexing 的封装。Poller 是Event Loop的间接成员,直供其所属Event Loop 在IO线程 调用,因此无需加锁,其生命期与Event Loop 一样,Poller 不拥有Channel ,Channel 在析构的时候需要自己注销,避免空悬指针。

Poller 供 EventLoop 调用的函数目前只有两个:poll() 和 updateChannel()。

1、学习笔记

  1. Poller::poll() 是Poller 的核心功能,调用poll() 获得当前活动的IO 事件,然后填充调用方传入的activeChannels 。
  2. Poller::fillActiveChannels() 遍历 pollfds_,找出有活动事件的fd,将fd对应的Channel 填入 activeChannel。当前活动事件revents会保存在Channel 中,供Channel::handleEvent() 处理。

这里我们不能一边遍历pollfds_, 一边调用Channel::handleEvent(), 因为Channel::handleEvent() 会添加或者删除Channel,从而造成pollfds_ 在遍历期间改变大小。

Poller 只负责IO multiplexing , 不负责事件的分发。

  1. Poller::updateChannel() 的主要功能是负责维护和更新pollfds_ 数组。
  2. 如果某个Channel 暂时不关心任何事件,就将pollfd.fd 设为-1,让poll 忽略此项。
    这里可以进一步改进为: 将pollfd.fd 设为 channel->fd() 的相反数 减1 ,这样可以进一步检查invariant。
    考虑为什么是 -1? 因为文件描述符0、1、2分别表示标准输入、标准输出、标准错误。-1、-2、-3 可分别表示忽略 标准输入、标准输出、标准错误。

2、代码

==================================Poller.cc ====================================

#include "Poller.h"
#include "Channel.h"

#include <assert.h>
#include <poll.h>

Poller::Poller(EventLoop * loop)
	:ownerLoop_(loop)
{
}

Poller::~Poller()
{
}

void Poller::poll(ChannelList * activeChannels)
{
	int numEvents = ::poll(&*pollfds_.begin(),pollfds_.size(),-1);
	if(numEvents > 0)
	{
		std::cout << numEvents << " events happened\n";
		fillActiveChannels(numEvents,activeChannels);}
	else if(numEvents == 0){
		std::cout << "nothing happened\n" ;}
	else{
		std::cout << "Poller::poll error\n";}
}

void Poller::fillActiveChannels(int numEvents,ChannelList * activeChannels) const
{
	for(PollFdList::const_iterator pfd = pollfds_.begin(); pfd != pollfds_.end() && numEvents >0 ;++pfd)
	{
	  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);
		activeChannels->push_back(channel);
	   }
	}
}

void Poller::updateChannel(Channel * channel)
{
	assertInLoopThread();
	std::cout << "fd = " << channel->fd() << "events = " << channel->events();
	if(channel->index() < 0)
	{
		assert(channels_.find(channel->fd()) == channels_.end());
		struct pollfd pfd;
		pfd.fd = channel->fd(); //将这个新的channel的fd 给 pfd
		pfd.events = static_cast<short>(channel->events());
		pfd.revents = 0;
		pollfds_.push_back(pfd);
		int idx = static_cast<int>(pollfds_.size()-1);
		channel->set_index(idx);
		channels_[pfd.fd] = channel;}   //key为 fd,value为channel
	else { //这个channel 是一个旧的channel,更新
		assert(channels_.find(channel->fd()) != channels_.end());
		assert(channels_[channel->fd()] == channel); 
		int idx = channel->index();
		assert(0 <= idx && idx < static_cast<int> (pollfds_.size()));
		struct pollfd &  pfd = pollfds_[idx];
		assert(pfd.fd == channel->fd() || pfd.fd == -1);
		pfd.events = static_cast<short>(channel->events());
		pfd.revents = 0;
		if(channel->isNoneEvent()){ 
			pfd.fd = -1; 
		}
	}
}

==================================Poller.h ====================================

#ifndef _POLLER_H
#define _POLLER_H

#include <map>
#include <vector>

#include "EventLoop.h"

struct pollfd;  //向前声明

class Channel;


class Poller : boost::noncopyable
{
  public:
	typedef std::vector<Channel *> ChannelList;

	Poller(EventLoop * loop);
	~Poller();
	void poll(ChannelList * activeChannels);

	void updateChannel(Channel * channel);

	void assertInLoopThread() { 
		bool f = ownerLoop_->isInLoopThread();
		if(!f)
			std::cout << "Not in its own thread\n";}

  private:
	void fillActiveChannels(int numEvents, ChannelList * activeChannel) const;

	typedef std::vector<struct pollfd> PollFdList;
	typedef std::map<int, Channel *> ChannelMap; 
	
	EventLoop * ownerLoop_;
	PollFdList pollfds_;
	ChannelMap channels_;
};

#endif

分类 Muduo网络库编程 学习笔记

本文摘自陈硕老师的linux多线程服务端编程

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值