彻底学会使用epoll(三)——ET的读操作实例分析

简介: 首先看程序一,这个程序想要实现的功能是当用户从控制台有任何输入操作时,输出”hello world!”。 l 程序一    点击(此处)折叠或打开 #include unistd.

首先看程序一,这个程序想要实现的功能是当用户从控制台有任何输入操作时,输出hello world

程序一

  

点击(此处)折叠或打开

  1. #include unistd.h>
  2. #include iostream>
  3. #include sys/epoll.h>
  4. using namespace std;
  5. int main(void)
  6. {
  7.     int epfd,nfds;
  8.     struct epoll_event ev,events[5];//ev用于注册事件,数组用于返回要处理的事件
  9.     epfd=epoll_create(1);//只需要监听一个描述符——标准输入
  10.     ev.data.fd=STDIN_FILENO;
  11.     ev.events=EPOLLIN|EPOLLET;//监听读状态同时设置ET模式
  12.     epoll_ctl(epfd,EPOLL_CTL_ADD,STDIN_FILENO,&ev);//注册epoll事件
  13.     for(;;)
  14.    {
  15.      nfds=epoll_wait(epfd,events,5,-1);
  16.      for(int i=0;infds;i++)
  17.      {
  18.         if(events[i].data.fd==STDIN_FILENO)
  19.            cout"hello world!"endl;
  20.      }
  21.    }
  22. }

运行结果:

程序一中对标准输入的监听使用ET模式,结果实现了我们想要的功能。那么实际原理是如何呢,我们将过程分析一下:

(1) 当用户输入一组字符,这组字符被送入buffer,字符停留在buffer中,又因为buffer由空变为不空,所以ET返回读就绪,输出hello world

(2) 之后程序再次执行epoll_wait,此时虽然buffer中有内容可读,但是根据我们上节的分析,ET并不返回就绪,导致epoll_wait阻塞。(底层原因是ET下就绪fdepitem只被放入rdlist一次)。

(3) 用户再次输入一组字符,导致buffer中的内容增多,根据我们上节的分析这将导致fd状态的改变,是对应的epitem再次加入rdlist,从而使epoll_wait返回读就绪,再次输出“hello world!”。

 我们在看看LT的情况如何,将程序以下修改:

    ev.events=EPOLLIN;//默认使用LT模式

运行结果:

结果正如我们所料,程序出现死循环,因为用户输入任意数据后,数据被送入buffer且没有被读出,所以LT模式下每次epoll_wait都认为buffer可读返回读就绪。导致每次都会输出hello world。下面在看程序二。

程序二


点击(此处)折叠或打开

  1. #include unistd.h>
  2. #include iostream>
  3. #include sys/epoll.h>
  4. using namespace std;
  5. int main(void)
  6. {
  7.     int epfd,nfds;
  8.     char buf[256];
  9.     struct epoll_event ev,events[5];//ev用于注册事件,数组用于返回要处理的事件
  10.     epfd=epoll_create(1);//只需要监听一个描述符——标准输入
  11.     ev.data.fd=STDIN_FILENO;
  12.     ev.events=EPOLLIN;//使用默认LT模式
  13.     epoll_ctl(epfd,EPOLL_CTL_ADD,STDIN_FILENO,&ev);//注册epoll事件
  14.     for(;;)
  15.    {
  16.      nfds=epoll_wait(epfd,events,5,-1);
  17.      for(int i=0;infds;i++)
  18.      {
  19.        if(events[i].data.fd==STDIN_FILENO)
  20.        {
  21.           read(STDIN_FILENO,buf,sizeof(buf));//将缓冲中的内容读出
  22.           cout"hello world!"endl;
  23.        }
  24.     }
  25.   }
  26. }

运行结果:

程序二依然使用LT模式,但是每次epoll_wait返回读就绪的时候我们都将buffer(缓冲)中的内容read出来,所以导致buffer再次清空,下次调用epoll_wait就会阻塞。所以能够实现我们所想要的功能——当用户从控制台有任何输入操作时,输出hello world。我们再来看看程序三。

程序三


点击(此处)折叠或打开

  1. int main(void)
  2. {
  3.     int epfd,nfds;
  4.     struct epoll_event ev,events[5];//ev用于注册事件,数组用于返回要处理的事件
  5.     epfd=epoll_create(1);//只需要监听一个描述符——标准输入
  6.     ev.data.fd=STDIN_FILENO;
  7.     ev.events=EPOLLIN|EPOLLET;//使用默认LT模式
  8.     epoll_ctl(epfd,EPOLL_CTL_ADD,STDIN_FILENO,&ev);//注册epoll事件
  9.     for(;;)
  10.    {
  11.      nfds=epoll_wait(epfd,events,5,-1);
  12.      for(int i=0;infds;i++)
  13.      {
  14.        if(events[i].data.fd==STDIN_FILENO)
  15.         {
  16.           cout"hello world!"endl;
  17.           ev.data.fd=STDIN_FILENO;
  18.           ev.events=EPOLLIN|EPOLLET;//使用默认LT模式
  19.           epoll_ctl(epfd,EPOLL_CTL_MOD,STDIN_FILENO,&ev);//重新MOD事件(ADD无效)
  20.         }
  21.      }
  22.    }
  23. }

程序三依然使用ET,但是每次读就绪后都主动的再次MOD IN事件,我们发现程序再次出现死循环,也就是每次返回读就绪。这就验证了上一节讨论ET读就绪的第三种情况。但是注意,如果我们将MOD改为ADD,将不会产生任何影响。别忘了每次ADD一个描述符都会在epitem组成的红黑树中添加一个项,我们之前已经ADD过一次,再次ADD将阻止添加,所以在次调用ADD IN事件不会有任何影响。

目录
相关文章
|
SQL 存储 数据库
基于Web技术的在线考试系统的设计与实现(论文+源码)_kaic
基于Web技术的在线考试系统的设计与实现(论文+源码)_kaic
|
9月前
|
搜索推荐 测试技术 API
探秘电商API:从测试到应用的深度解析与实战指南
电商API是电子商务背后的隐形引擎,支撑着从商品搜索、购物车更新到支付处理等各个环节的顺畅运行。它通过定义良好的接口,实现不同系统间的数据交互与功能集成,确保订单、库存和物流等信息的实时同步。RESTful、GraphQL和WebSocket等类型的API各自适用于不同的应用场景,满足多样化的需求。在测试方面,使用Postman、SoapUI和jMeter等工具进行全面的功能、性能和安全测试,确保API的稳定性和可靠性。未来,随着人工智能、大数据和物联网技术的发展,电商API将进一步智能化和标准化,为用户提供更个性化的购物体验,并推动电商行业的持续创新与进步。
331 5
|
12月前
|
C#
C# 图形验证码实现登录校验代码
C# 图形验证码实现登录校验代码
282 2
|
存储 Windows
卸载时报错:“系统找不到指定的驱动器”问题处理
【10月更文挑战第5天】文档介绍了分析“系统找不到指定的驱动器”错误的原因及解决方法。此错误多因外部设备移除、网络驱动器断开或软件卸载程序缺陷引起。解决策略包括检查外部设备连接、更新驱动器盘符、使用第三方卸载工具以及手动清理注册表和文件系统。
3915 3
|
存储 传感器 数据可视化
3D目标检测数据集 KITTI(标签格式解析、3D框可视化、点云转图像、BEV鸟瞰图)
本文介绍在3D目标检测中,理解和使用KITTI 数据集,包括KITTI 的基本情况、下载数据集、标签格式解析、3D框可视化、点云转图像、画BEV鸟瞰图等,并配有实现代码。
3552 1
idea 查看类的继承结构及其子类
idea 查看类的继承结构及其子类
219 5
|
SQL 数据采集 存储
"揭秘SQL Server中REPLACE函数的神奇力量!一键替换字符串,解锁数据处理的无限可能,你还在等什么?"
【8月更文挑战第20天】SQL Server 的 REPLACE 函数是处理字符串的强大工具,用于在查询中替换字符串的部分内容。基本语法为 `REPLACE(string_expression, string_pattern, string_replacement)`。例如,可将员工邮箱从 `@example.com` 替换为 `@newdomain.com`。支持多级嵌套替换与变量结合使用,适用于动态生成查询。注意大小写敏感性及全局替换特性。掌握 REPLACE 函数能有效提升数据处理能力。
673 0
|
机器学习/深度学习 人工智能 算法
探索未来:量子计算的奥秘与挑战
本文旨在揭示量子计算技术背后的科学原理,并探讨其在未来科技革命中的潜力与面临的挑战。通过分析量子位的特殊性质、量子纠缠现象以及量子算法的优势,我们展望了量子计算在多个领域的应用前景,同时指出了当前技术发展的主要障碍。
|
JavaScript 安全 前端开发
在Vue中实现回车键切换焦点
在Vue中实现回车键切换焦点
701 0
|
机器学习/深度学习 自动驾驶 算法
为什么你的模型效果这么差,深度学习调参有哪些技巧?
为了防止这些错误发生,Josh给出的建议是:尽可能减少代码的行数,使用现成的组件,然后再构建复杂的数据pipeline。
为什么你的模型效果这么差,深度学习调参有哪些技巧?