源码下载以及安装点击链接https://blog.youkuaiyun.com/YoungSusie/article/details/90021742
Poller class是IO multiplexing 的封装。Poller 是Event Loop的间接成员,直供其所属Event Loop 在IO线程 调用,因此无需加锁,其生命期与Event Loop 一样,Poller 不拥有Channel ,Channel 在析构的时候需要自己注销,避免空悬指针。
Poller 供 EventLoop 调用的函数目前只有两个:poll() 和 updateChannel()。
1、学习笔记
- Poller::poll() 是Poller 的核心功能,调用poll() 获得当前活动的IO 事件,然后填充调用方传入的activeChannels 。
- Poller::fillActiveChannels() 遍历 pollfds_,找出有活动事件的fd,将fd对应的Channel 填入 activeChannel。当前活动事件revents会保存在Channel 中,供Channel::handleEvent() 处理。
这里我们不能一边遍历pollfds_, 一边调用Channel::handleEvent(), 因为Channel::handleEvent() 会添加或者删除Channel,从而造成pollfds_ 在遍历期间改变大小。
Poller 只负责IO multiplexing , 不负责事件的分发。
- Poller::updateChannel() 的主要功能是负责维护和更新pollfds_ 数组。
- 如果某个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
本文摘自陈硕老师的linux多线程服务端编程