这一节我们来解析Reactor最核心的事件分发机制——Channel和Poller。每个Channel对象只属于一个EventLoop,因此每个Channel对象都只属于一个IO线程,并且只负责一个文件描述符,但是并不拥有这个fd,也不会在析构的时候关闭这个fd。首先来看一下构造函数原型Channel(EventLoop *loop, int fd);很明显,需要说明所属EventLoop,以及负责的文件描述符fd
事件类型的定义:
const int Channel::kNoneEvent = 0;
const int Channel::kReadEvent = POLLIN | POLLPRI;
const int Channel::kWriteEvent = POLLOUT;
事件处理函数:
void Channel::handleEvent()
{
eventHandling_ = true;
if (revents_ & POLLNVAL) {
LOG_WARN << "Channel::handle_event() POLLNVAL";
}
if ((revents_ & POLLHUP) && !(revents_ & POLLIN)) {
LOG_WARN << "Channel::handle_event() POLLHUP";
if (closeCallback_) closeCallback_();
}
if (revents_ & (POLLERR | POLLNVAL)) {
if (errorCallback_) errorCallback_();
}
if (revents_ & (POLLIN | POLLPRI | POLLRDHUP)) {
if (readCallback_) readCallback_();
}
if (revents_ & POLLOUT) {
if (writeCallback_) writeCallback_();
}
eventHandling_ = false;
}
update和disableAll用来注册和注销,其中update会调用EventLoop的updateChannel函数,disableAll 会将events设置为kNoneEvent.
Poller是对IO multiplexing的封装,在muduo中是个抽象基类,因为同时支持poll和epoll两种IO复用方式,和Channel类似,只属于一个EventLoop,只供其owner EventLoop在IO线程调用,所以无需加锁。我们先来看两个成员变量的类型:
typedef std::vector<pollfd> PollfdList;
typedef std::map<int, Channel*> ChannelMap;
PollfdList pollfds_;
ChannelMap channels_;
PollfdList是一个vector,保存着pollfd,ChannelMap是一个map,保存着Channel*。key为fd,value为Channel*。Channel的index为在pollfds_中的下标。
updateChannel用来注册和修改channel,removeChannel用来注销channel。