muduo库源码剖析(一) reactor模式
一. Reactor模式简介
Reactor释义“反应堆”,是一种事件驱动机制。和普通函数调用的不同之处在于:应用程序不是主动的调用某个API完成处理,而是恰恰相反,Reactor逆置了事件处理流程,应用程序需要提供相应的接口并注册到Reactor上,如果相应的时间发生,Reactor将主动调用应用程序注册的接口,这些接口又称为“回调函数”。
二. moduo库Reactor模式的实现
muduo主要通过3个类来实现Reactor模式:EventLoop,Channel,Poller。
1. EventLoop
事件循环。moduo的线程模型为one loop per thread,即每个线程只能有一个EventLoop对象。EventLoop对象的生命周期通常和其所属的线程一样长。
数据成员:
const pid_t threadId_;保存当前EventLoop所属线程id
boost::scoped_ptr poller_; 实现I/O复用 boost::scoped_ptr timerQueue_;
int wakeupFd_;
boost::scoped_ptr wakeupChannel_; 用于处理wakeupFd_上的可读事件,将事件分发到handlRead() ChannelList activeChannels_; 有事件就绪的 Channel Channel* currentActiveChannel_;
MutexLock mutex_; pendingFunctors_回暴露给其他线程,所以需要加锁 std::vectorpendingFunctors_;
主要功能函数:
loop(),在该函数中会循环执行以下过程:调用Poller::poll(),通过此调用获得一个vector<channel*>activeChannels_的就绪事件集合,再遍历该容器,执行每个Channel的Channel::handleEvent()完成相应就绪事件回调,最后执行pendingFunctors_排队的函数。上述一次循环就是一次Reactor模式完成。
runInLoop(boost::function<void()>),实现用户指定任务回调,若是EventLoop隶属的线程调用EventLoop::runInLoop()则EventLoop马上执行;若是其它线程调用则执行EventLoop::queueInLoop(boost::function<void()>将任务添加到队列中(线程转移)。EventLoop如何获得有任务这一事实呢?通过eventfd可以实现线程间通信,具体做法是:其它线程向EventLoop::vector<boost::function<void()> >添加任务T,然后通过EventLoop::wakeup()向eventfd写一个int,eventfd的回调函数EventLoop::handleRead()读取这个int,从而相当于EventLoop被唤醒,此时loop中遍历队列执行堆积的任务。这里采用Channel管理eventfd,Poller侦听eventfd体现了eventfd可以统一事件源的优势。
queueInLoop(Functor& cb),将cb放入队列,并在必要时唤醒IO线程。有两种情况需要唤醒IO线程,1 调用queueInLoop()的线程不是IO线程,2 调用queueInLoop()的线程是IO线程,而此时正在调用pengding functor。
2. Channel
事件分发器。每个Channel只属于一个EventLoop,每个Channel只负责一个文件描述符fd的IO事件分发,但其不拥有fd。
数据成员:
int fd_文件描述符,
int events_ 文件描述符注册事件,
int revents_文件描述符的就绪事件,由Poller::poll设置
readCallback_,writeCallback...各种事件回调,会在拥有该Channel类的构造函数中被注册,例如TcpConnction会在构造函数中TcpConnection::handlRead()注册给Channel::readCallback
主要功能函数:
setCallback()系列函数,接受Channel所属的类注册相应的事件回调函数
enableReading(),update(), 当一个fd想要注册可读事件时,首先通过Channel::enableReading()-->Channel::update(this)->EventLoop::updateChannel(Channel)->Poller::updateChannel(Channel*)调用链向poll系统调用的侦听事件表注册或者修改注册事件。
handleEvent(), Channel作为是事件分发器其核心结构是Channel::handleEvent(),该函数调用Channel::handleEventWithGuard(),在其内根据Channel::revents的值分发调用相应的事件回调。
3. Poller
Poller是IO multiplexing的封装,封装了poll和epoll。Poller是EventLoop的间接成员,只供拥有该Poller的EventLoop在IO线程调用。生命期与EventLoop相等。
数据成员:
vector pollfds_事件结构体数组用于poll的第一个参数;
map<int,channel*> channels_用于文件描述符fd到Channel的映射便于快速查找到相应的Channel
主要功能函数:
updateChannel(Channel*) 用于将传入的Channel关心的事件注册给Poller。
poll(int timeoutMs,vector<channel*> activeChannels)其调用poll侦听事件集合,将就绪事件所属的Channel调用fillActiveChannels()加入到activeChannels_中。
其他类
EventLoopThread: 启动一个线程执行一个EventLoop,其语义和"one loop per thread“相吻合。注意这里用到了互斥量和条件变量,这是因为线程A创建一个EventLoopThread对象后一个运行EventLoop的线程已经开始创建了,可以通过EventLoopThread::startLoop()获取这个EventLoop对象,但是若EventLoop线程还没有创建好,则会出错。所以在创建EventLoop完成后会执行condititon.notify()通知线程A,线程A调用EventLoopThread::startLoop()时调用condition.wai()等待,从而保证获取一个创建完成的EventLoop.毕竟线程A创建的EventLoop线程,A可能还会调用EventLoop执行一些任务回调呢。
转自:http://www.cnblogs.com/nicganon/p/3741609.html
muduo库源码剖析(一) reactor模式的更多相关文章
- muduo库源码剖析(二) 服务端
一. TcpServer类: 管理所有的TCP客户连接,TcpServer供用户直接使用,生命期由用户直接控制.用户只需设置好相应的回调函数(如消息处理messageCallback)然后TcpSer ...
- caffe库源码剖析——net层
net层的功能实现主要涉及到net.hpp和net.cpp文件,让我们要捋顺它是干了什么,是如何实现的. 1. net层使用到的参数 第一步要做的事,就是查看caffe.proto文件,弄清楚net都 ...
- ucore 源码剖析
lab1 源码剖析 从实模式到保护模式 初始化ds,es和ss等段寄存器为0 使能A20门,其中seta20.1写数据到0x64端口,表示要写数据给8042芯片的Output Port;seta20. ...
- Golang 源码剖析:log 标准库
Golang 源码剖析:log 标准库 原文地址:Golang 源码剖析:log 标准库 日志 输出 2018/09/28 20:03:08 EDDYCJY Blog... 构成 [日期]<空格 ...
- 设计模式(二十二)——状态模式(APP抽奖活动+借贷平台源码剖析)
24.1 APP 抽奖活动问题 请编写程序完成 APP 抽奖活动 具体要求如下: 1) 假如每参加一次这个活动要扣除用户 50 积分,中奖概率是 10% 2) 奖品数量固定,抽完就不能抽奖 3) 活动 ...
- Apache Spark源码剖析
Apache Spark源码剖析(全面系统介绍Spark源码,提供分析源码的实用技巧和合理的阅读顺序,充分了解Spark的设计思想和运行机理) 许鹏 著 ISBN 978-7-121-25420- ...
- DICOM医学图形处理:storescp.exe与storescu.exe源码剖析,学习C-STORE请求(续)
转载:http://blog.csdn.net/zssureqh/article/details/39237649 背景: 上一篇博文中,在对storescp工具源文件storescp.cc和DcmS ...
- DICOM医学图像处理:storescp.exe与storescu.exe源码剖析,学习C-STORE请求
转载:http://blog.csdn.net/zssureqh/article/details/39213817 背景: 上一篇专栏博文中针对PACS终端(或设备终端,如CT设备)与RIS系统之间w ...
- 《Apache Spark源码剖析》
Spark Contributor,Databricks工程师连城,华为大数据平台开发部部长陈亮,网易杭州研究院副院长汪源,TalkingData首席数据科学家张夏天联袂力荐1.本书全面.系统地介绍了 ...
随机推荐
- kafka启动时出现FATAL Fatal error during KafkaServer startup. Prepare to shutdown (kafka.server.KafkaServer) java.io.IOException: Permission denied错误解决办法(图文详解)
首先,说明,我kafk的server.properties是 kafka的server.properties配置文件参考示范(图文详解)(多种方式) 问题详情 然后,我启动时,出现如下 [hadoop ...
- nodejs安装node-rsa遇到的问题及解决
nodejs第一次使用,故碰到一些小白问题: 1.使用 npm install node-rsa -S 2.封装rsa import NodeRSA from 'node-rsa'; const rs ...
- CF798C Mike and gcd problem
思路: 首先如果数列的最大公约数大于1,直接输出即可. 否则,设对原数列中的ai和ai+1进行一次操作,分别变为ai - ai+1和ai + ai+1.设新数列的最大公约数为d,则由于d|(ai - ...
- CF817B Makes And The Product
思路: 模拟,数学. 实现: #include <iostream> #include <cstdio> #include <algorithm> using na ...
- 1619. [HEOI2012]采花
1619. [HEOI2012]采花 ★★☆ 输入文件:1flower.in 输出文件:1flower.out 简单对比 时间限制:5 s 内存限制:128 MB [题目描述] 萧薰儿 ...
- Tornado引入静态css、js文件
一.静态路径 template_path=os.path.join(os.path.dirname(__file__), "templates") 这里是设置了模板的路径,放置模板 ...
- JBoss4.2的启动方式-Jboss无法通过IP地址访问,只能用localhost访问
JBOSS版本:4.2.3GA症状:服务器无法通过IP地址去访问,只能用127.0.0.1或者localhost来访问. 开始怀疑是端口没有放开,用telnet ip 80 也不能连接,就一直怀疑端口 ...
- 浏览器的两种模式quirks mode 和strict mode
关键字: javascript.quirks mode.strict mode 在看js代码时,有时会看到关于quirks mode(怪异模式)和strict mode(严格格式)的东西,一直也没深究 ...
- DIV自动居中
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/ ...
- java正则表达式匹配字符
假设要匹配${2}中间为数字的这个类型的变量String,则 Pattern p = Pattern.compile("\\$\\{\\d+\\}"); Matcher m = p ...