(转)彻底学会使用epoll(一)——ET模式实现分析

注:之前写过两篇关于epoll实现的文章,但是感觉懂得了实现原理并不一定会使用,所以又决定写这一系列文章,希望能够对epoll有比较清楚的认识。是请大家转载务必注明出处,算是对我劳动成果的一点点尊重吧。另外,文中如果有不全面或者不正确的地方还请大家指出。也可以私信或者发邮件:lvyilong316@163.com

1. ET模式实现分析

1.1 ET和LT的实现区别

    首先给出下面一张图,这张图是从我之前的一篇博文——epoll实现分析中摘取并细化的。这张图对理解ET模式已经epoll的工作过程只管重要,当然我自己总结出来后也感觉有的小成就,在这里与大家分享。

注:上图的poll不要理解成和select相似那个poll,这是通过epoll_ctl调用的。

下面简要分析一下epoll的工作过程:

(1) epoll_wait调用ep_poll,当rdlist为空(无就绪fd)时挂起当前进程,知道rdlist不空时进程才被唤醒。

(2) 文件fd状态改变(buffer由不可读变为可读或由不可写变为可写),导致相应fd上的回调函数ep_poll_callback()被调用。

(3) ep_poll_callback将相应fd对应epitem加入rdlist,导致rdlist不空,进程被唤醒,epoll_wait得以继续执行。

(4) ep_events_transfer函数将rdlist中的epitem拷贝到txlist中,并将rdlist清空。

(5) ep_send_events函数(很关键),它扫描txlist中的每个epitem,调用其关联fd对用的poll方法(图中蓝线)。此时对poll的调用仅仅是取得fd上较新的events(防止之前events被更新),之后将取得的events和相应的fd发送到用户空间(封装在struct epoll_event,从epoll_wait返回)。之后如果这个epitem对应的fd是LT模式监听且取得的events是用户所关心的,则将其重新加入回rdlist(图中蓝线),否则(ET模式)不在加入rdlist。

具体代码:

/* 扫描整个txlist链表... */

for (eventcnt = 0, uevent = esed->events;

     !list_empty(head) && eventcnt < esed->maxevents;) {

/* 取出第一个成员 */

epi = list_first_entry(head, struct epitem, rdllink);

/* 然后从链表里面移除 */

list_del_init(&epi->rdllink);

/* 读取events, 

 * 注意events我们ep_poll_callback()里面已经取过一次了, 为啥还要再取?

 * 1. 我们当然希望能拿到此刻的最新数据, events是会变的~

 * 2. 不是所有的poll实现, 都通过等待队列传递了events, 有可能某些驱动压根没传

 * 必须主动去读取. */

revents = epi->ffd.file->f_op->poll(epi->ffd.file, NULL) &

epi->event.events;

 

if (revents) {

/* 将当前的事件和用户传入的数据都copy给用户空间,

 * 就是epoll_wait()后应用程序能读到的那一堆数据. */

if (__put_user(revents, &uevent->events) ||

    __put_user(epi->event.data, &uevent->data)) {

/* 如果copy过程中发生错误, 会中断链表的扫描,

 * 并把当前发生错误的epitem重新插入到ready list.

 * 剩下的没处理的epitem也不会丢弃, 在ep_scan_ready_list()

 * 中它们也会被重新插入到ready list */

list_add(&epi->rdllink, head);

return eventcnt ? eventcnt : -EFAULT;

}

eventcnt++;

uevent++;

if (epi->event.events & EPOLLONESHOT)

epi->event.events &= EP_PRIVATE_BITS;

else if (!(epi->event.events & EPOLLET)) {

/*

 * If this file has been added with Level

 * Trigger mode, we need to insert back inside

 * the ready list, so that the next call to

 * epoll_wait() will check again the events

 * availability. At this point, noone can insert

 * into ep->rdllist besides us. The epoll_ctl()

 * callers are locked out by

 * ep_scan_ready_list() holding "mtx" and the

 * poll callback will queue them in ep->ovflist.

 */

/* 嘿嘿, EPOLLET和非ET的区别就在这一步之差呀~

 * 如果是ET, epitem是不会再进入到readly list,

 * 除非fd再次发生了状态改变, ep_poll_callback被调用.

 * 如果是非ET, 不管你还有没有有效的事件或者数据,

 * 都会被重新插入到ready list, 再下一次epoll_wait

 * 时, 会立即返回, 并通知给用户空间. 当然如果这个

 * 被监听的fds确实没事件也没数据了, epoll_wait会返回一个0,

 * 空转一次.

 */

list_add_tail(&epi->rdllink, &ep->rdllist);

}

}

}

说明:

epoll_wait返回的条件是rdlist不空,而使rdlist不空的途径有两个,分别对应图中的红线和蓝线。

ET和LT模式下的epitem都可以通过红线方式加入rdlist从而唤醒epoll_wait,但LT模式下的epitem还可以通过蓝线方式重新加入rdlist唤醒epoll_wait。所以ET模式下,fd就绪(通过红线加入rdlist)只会被通知一次,而LT模式下只要满足相应读写条件就返回就绪(通过蓝线加入rdlist)。

ET事件发生仅通知一次的原因是只被添加到rdlist中一次,而LT可以有多次添加的机会。

1.2 两种加入rdlist途径的不同

下面我们来分析一下图中两种将epitem加入rdlist方式(也就是红线和蓝线)的区别。

红线:fd状态改变是才会触发。那么什么情况会导致fd状态的改变呢?

对于读取操作:

(1) 当buffer由不可读状态变为可读的时候,即由空变为不空的时候。

(2) 当有新数据到达时,即buffer中的待读内容变多的时候。

对于写操作:

(1) 当buffer由不可写变为可写的时候,即由满状态变为不满状态的时候。

(2) 当有旧数据被发送走时,即buffer中待写的内容变少得时候。

蓝线:fd的events中有相应的时间(位置1)即会触发。那么什么情况下会改变events的相应位呢?

对于读操作:

(1) buffer中有数据可读的时候,即buffer不空的时候fd的events的可读为就置1。

对于写操作:

(1) buffer中有空间可写的时候,即buffer不满的时候fd的events的可写位就置1。

 

说明:红线是时间驱动被动触发,蓝线是函数查询主动触发。

 

原文:http://blog.chinaunix.net/xmlrpc.php?r=blog/article&uid=28541347&id=4273856

转载于:https://www.cnblogs.com/hznet/p/6097098.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/253929.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Apache 设置http跳转至HTTPS访问

为什么80%的码农都做不了架构师&#xff1f;>>> <VirtualHost>...</VirtualHost> 中添加如下配置 <IfModule mod_rewrite.c>RewriteEngine onRewriteCond %{SERVER_PORT} 80RewriteRule ^(.*)$ https://域名/$1 [R301,L] </IfModule> 转…

(二)功耗的分析

前面学习了进行低功耗的目的个功耗的构成&#xff0c;今天就来分享一下功耗的分析。由于是面向数字IC前端设计的学习&#xff0c;所以这里的功耗分析是基于DC中的power compiler工具&#xff1b;更精确的功耗分析可以采用PT&#xff0c;关于PT的功耗分析可以查阅其他资料&#…

Hibernate创建hqll时报错

Hibernate 问题,在执行Query session.createQuery(hql) 报错误 出错截图&#xff1a; 这条语句在java运行环境下&#xff0c;直接连数据库不出错&#xff0c;如果在hiberante,struts环境下就出错 出错原因&#xff1a;jar包冲突&#xff0c;struts2和hibernate框架中都有antlr包…

.NET Core TDD 前传: 编写易于测试的代码 -- 全局状态

第1篇: 讲述了如何创造"缝". "缝"(seam)是需要知道的概念. 第2篇, 避免在构建对象时写出不易测试的代码. 第3篇, 依赖项和迪米特法则. 本文是第4篇, 将介绍全局状态引起的问题. 全局状态 全局状态, 也可以叫做应用程序状态, 它是一组变量, 这些变量维护着…

(三)系统与架构级低功耗设计

前面讲解了使用EDA工具&#xff08;主要是power compiler&#xff09;进行功耗分析的流程&#xff0c;这里我们将介绍在数字IC中进行低功耗设计的方法&#xff0c;同时也结合EDA工具&#xff08;主要是Design Compiler&#xff09;如何实现。我们的讲解的低功耗设计主要是自顶向…

(四)RTL级低功耗设计

前面介绍了系统级的低功耗设计&#xff0c;换句话说就是在系统级降低功耗可以考虑的方面。系统级的低功耗设计&#xff0c;主要是由系统级设计、具有丰富经验的人员实现&#xff0c;虽然还轮不到我们设计&#xff0c;我们了解一下还是比较好的。我们前端设计人员的重点不在系统…

Unity3D 游戏前端开发技能树(思维导图)

如果做游戏也是一种游戏,那么这个游戏的自由度实在是太高了.(导图源文件链接&#xff1a;http://pan.baidu.com/s/1eSHpH5o 密码&#xff1a;qzl5) 最近要用思维导图软件Xmind把自己的思路好好捋一捋,算是温故知新吧. 转载于:https://www.cnblogs.com/qiaogaojian/p/6098962.ht…

SQL Server 死锁的告警监控

原文:SQL Server 死锁的告警监控今天这篇文章总结一下如何监控SQL Server的死锁&#xff0c;其实以前写过MS SQL 监控错误日志的告警信息&#xff0c;这篇文章着重介绍如何监控数据库的死锁&#xff0c;当然这篇文章不分析死锁产生的原因、以及如何解决死锁。死锁&#xff08;D…

关于web性能一些特性汇总

关于web性能一些特性汇总 DOMContentLoaded & load load事件是window对象上的事件。指的是网页资源已经加载完毕&#xff08;包括但不限于DOM、图片、音频、脚本、插件资源以及CSS&#xff09;。 DOMContentLoaded事件是document对象上的事件。指的是DOM已经加载完毕。IE中…

(五)门级电路低功耗设计优化

&#xff08;1&#xff09;门级电路的功耗优化综述 门级电路的功耗优化(Gate Level Power Optimization&#xff0c;简称GLPO)是从已经映射的门级网表开始&#xff0c;对设计进行功耗的优化以满足功耗的约束&#xff0c;同时设计保持其性能&#xff0c;即满足设计规则和时序的要…

Spring3向Spring4升级过程中quartz修改

为什么80%的码农都做不了架构师&#xff1f;>>> 问题 nested exception is org.springframework.beans.factory.CannotLoadBeanClassException: Cannot find class [org.springframework.scheduling.quartz.CronTriggerBean] for bean with name ... 原因 org.spri…

EasyUI--messager

1.    alert 方法 <script type"text/javascript">$( function(){$.messager.alert("调用messager","文本内容") ;});</script> 这里还可以通过icon添加相应的图标及info加入回调函数 <script type"text/javascript&quo…

Redis学习第八课:Redis高级实用特性(一)

Redis高级实用特性 注&#xff1a;我学习的环境是vmware7.1 ubantu10.10 redis 3.0.2 1、安全性 设置客户端连接后进行任何其他指定前需要的密码。因为redis速度相当快&#xff0c;一个外部用户可以在一秒钟进行很多次的密码尝试&#xff0c;这就需要设定非常强大的密码来防止…

分布式缓存的面试题9

1、面试题 如何保证缓存与数据库的双写一致性&#xff1f; 2、面试官心里分析 你只要用缓存&#xff0c;就可能会涉及到缓存与数据库双存储双写&#xff0c;你只要是双写&#xff0c;就一定会有数据一致性的问题&#xff0c;那么你如何解决一致性问题&#xff1f; 3、面试题剖析…

ROS与navigation教程——概述

navigation是ROS的二维导航功能包&#xff0c;简单来说&#xff0c;就是根据输入的里程计等传感器的信息流和机器人的全局位置&#xff0c;通过导航算法&#xff0c;计算得出安全可靠的机器人速度控制指令。 代码库&#xff1a;https://github.com/ros-planning/navigation 代…

【设计模式】单例模式 Singleton Pattern

通常我们在写程序的时候会碰到一个类只允许在整个系统中只存在一个实例&#xff08;Instance&#xff09; 的情况&#xff0c; 比如说我们想做一计数器&#xff0c;统计某些接口调用的次数&#xff0c;通常我们的数据库连接也是只期望有一个实例。Windows系统的系统任务管理器…

进程及线程通信总结

上文我们介绍了如何建立一个简单的多线程程序&#xff0c;多线程之间不可避免的需要进行通信 。相比于进程间通信来说&#xff0c;线程间通信无疑是相对比较简单的。 首先我们来看看最简单的方法&#xff0c;那就是使用全局变量&#xff08;静态变量也可以&#xff09;来进行通…

ROS multi-master——multimaster_fkie配置

多主站ROS配置和mutimaster_fkie ROS版本&#xff1a;kinetic 操作系统&#xff1a;Ubuntu 16.04。 multimaster_fkie&#xff1a;github 1网络配置 1.1路由器 设置无线路由器并连接两台计算机/机器人。为这两台计算机设置静态IP地址。相互测试ping命令和ssh。 1.2主机 …

Docker入门

1. Docker简介: docker是一个基于LXC的高级容器引擎。简单地说&#xff0c;docker是一个轻量级的虚拟解决方案&#xff0c;或者说它是一个超轻量级的虚拟机&#xff08;容器&#xff09;。 Docker是一个开源的引擎&#xff0c;可以轻松的为任何应用创建一个轻量级的、可移植的、…

Gmapping——从原理到实践

概述 在SLAM中&#xff0c;机器人位姿和地图都是状态变量&#xff0c;我们需要同时对这两个状态变量进行估计&#xff0c;即机器人获得一张环境地图的同时确定自己相对于该地图的位置。我们用x表示机器人状态&#xff0c;m表示环境地图&#xff0c;z表示传感器观测情况&#xf…