博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
epoll 水平触发与边缘触发
阅读量:4097 次
发布时间:2019-05-25

本文共 3843 字,大约阅读时间需要 12 分钟。

epoll也是实现I/O多路复用的一种方法,为了深入了解epoll的原理,我们先来看下epoll水平触发(level trigger,LT,LT为epoll的默认工作模式)与边缘触发(edge trigger,ET)两种工作模式。

使用脉冲信号来解释LT和ET可能更加贴切。Level是指信号只需要处于水平,就一直会触发;而edge则是指信号为上升沿或者下降沿时触发。说得还有点玄乎,我们以生活中的一个例子来类比LT和ET是如何确定读操作是否就绪的。

水平触发 

儿子:妈妈,我收到了500元的压岁钱。 
妈妈:嗯,省着点花。 
儿子:妈妈,我今天花了200元买了个变形金刚。 
妈妈:以后不要乱花钱。 
儿子:妈妈,我今天买了好多好吃的,还剩下100元。 
妈妈:用完了这些钱,我可不会再给你钱了。 
儿子:妈妈,那100元我没花,我攒起来了 
妈妈:这才是明智的做法! 
儿子:妈妈,那100元我还没花,我还有钱的。 
妈妈:嗯,继续保持。 
儿子:妈妈,我还有100元钱。 
妈妈:…

接下来的情形就是没完没了了:只要儿子一直有钱,他就一直会向他的妈妈汇报。LT模式下,只要内核缓冲区中还有未读数据,就会一直返回描述符的就绪状态,即不断地唤醒应用进程。在上面的例子中,儿子是缓冲区,钱是数据,妈妈则是应用进程了解儿子的压岁钱状况(读操作)。

边缘触发 

儿子:妈妈,我收到了500元的压岁钱。 
妈妈:嗯,省着点花。 
(儿子使用压岁钱购买了变形金刚和零食。) 
儿子: 
妈妈:儿子你倒是说话啊?压岁钱呢?

这个就是ET模式,儿子只在第一次收到压岁钱时通知妈妈,接下来儿子怎么把压岁钱花掉并没有通知妈妈。即儿子从没钱变成有钱,需要通知妈妈,接下来钱变少了,则不会再通知妈妈了。在ET模式下, 缓冲区从不可读变成可读,会唤醒应用进程,缓冲区数据变少的情况,则不会再唤醒应用进程。

我们再详细说明LT和ET两种模式下对读写操作是否就绪的判断。

水平触发

1. 对于读操作

只要缓冲内容不为空,LT模式返回读就绪。

2. 对于写操作

只要缓冲区还不满,LT模式会返回写就绪。

边缘触发

1. 对于读操作

(1)当缓冲区由不可读变为可读的时候,即缓冲区由空变为不空的时候。

(2)当有新数据到达时,即缓冲区中的待读数据变多的时候。

(3)当缓冲区有数据可读,且应用进程对相应的描述符进行EPOLL_CTL_MOD 修改EPOLLIN事件时。

2. 对于写操作

(1)当缓冲区由不可写变为可写时。

(2)当有旧数据被发送走,即缓冲区中的内容变少的时候。

(3)当缓冲区有空间可写,且应用进程对相应的描述符进行EPOLL_CTL_MOD 修改EPOLLOUT事件时。

实验

实验1

实验1对标准输入文件描述符使用ET模式进行监听。当我们输入一组字符并接下回车时,屏幕中会输出”hello world”。

#include 
#include
#include
int main(){ int epfd, nfds; struct epoll_event event, events[5]; epfd = epoll_create(1); event.data.fd = STDIN_FILENO; event.events = EPOLLIN | EPOLLET; epoll_ctl(epfd, EPOLL_CTL_ADD, STDIN_FILENO, &event); while (1) { nfds = epoll_wait(epfd, events, 5, -1); int i; for (i = 0; i < nfds; ++i) { if (events[i].data.fd == STDIN_FILENO) { printf("hello world\n"); } } }}

输出:

$ ./epoll1 

hello world 
abc 
hello world 
hello 
hello world 
ttt 
hello world

当用户输入一组字符,这组字符被送入缓冲区,因为缓冲区由空变成不空,所以ET返回读就绪,输出”hello world”。 

之后再次执行epoll_wait,但ET模式下只会通知应用进程一次,故导致epoll_wait阻塞。 
如果用户再次输入一组字符,导致缓冲区内容增多,ET会再返回就绪,应用进程再次输出”hello world”。 
如果将上面的代码中的event.events = EPOLLIN | EPOLLET;改成event.events = EPOLLIN;,即使用LT模式,则运行程序后,会一直输出hello world

实验2

实验2对标准输入文件描述符使用LT模式进行监听。当我们输入一组字符并接下回车时,屏幕中会输出”hello world”。

#include 
#include
#include
int main(){ int epfd, nfds; char buf[256]; struct epoll_event event, events[5]; epfd = epoll_create(1); event.data.fd = STDIN_FILENO; event.events = EPOLLIN; // LT是默认模式 epoll_ctl(epfd, EPOLL_CTL_ADD, STDIN_FILENO, &event); while (1) { nfds = epoll_wait(epfd, events, 5, -1); int i; for (i = 0; i < nfds; ++i) { if (events[i].data.fd == STDIN_FILENO) { read(STDIN_FILENO, buf, sizeof(buf)); printf("hello world\n"); } } }}

输出:

$ ./epoll2 

abc 
hello world 
eeeee 
hello world 
lihao 
hello world

实验2中使用的是LT模式,则每次epoll_wait返回时我们都将缓冲区的数据读完,下次再调用epoll_wait时就会阻塞,直到下次再输入字符。 

如果将上面的程序改为每次只读一个字符,那么每次输入多少个字符,则会在屏幕中输出多少个“hello world”。有意思吧。

实验3

实验3对标准输入文件描述符使用ET模式进行监听。当我们输入任何输入并接下回车时,屏幕中会死循环输出”hello world”。

#include 
#include
#include
int main(){ int epfd, nfds; struct epoll_event event, events[5]; epfd = epoll_create(1); event.data.fd = STDIN_FILENO; event.events = EPOLLIN | EPOLLET; epoll_ctl(epfd, EPOLL_CTL_ADD, STDIN_FILENO, &event); while (1) { nfds = epoll_wait(epfd, events, 5, -1); int i; for (i = 0; i < nfds; ++i) { if (events[i].data.fd == STDIN_FILENO) { printf("hello world\n"); event.data.fd = STDIN_FILENO; event.events = EPOLLIN | EPOLLET; epoll_ctl(epfd, EPOLL_CTL_MOD, STDIN_FILENO, &event); } } }}

实验3使用ET模式,但是每次读就绪后都主动对描述符进行EPOLL_CTL_MOD 修改EPOLLIN事件,由上面的描述我们可以知道,会再次触发读就绪,这样就导致程序出现死循环,不断地在屏幕中输出”hello world”。但是,如果我们将EPOLL_CTL_MOD 改为EPOLL_CTL_ADD,则程序的运行将不会出现死循环的情况。

参考资料

转载地址:http://uwlii.baihongyu.com/

你可能感兴趣的文章
【Unity】微信登录后将头像存为bytes,将bytes读取成sprite图片
查看>>
【Unity】使用GPS定位经纬度
查看>>
【UGUI/NGUI】一键换Text/Label字体
查看>>
【C#】身份证本地验证
查看>>
【Unity】坑爹的Bug
查看>>
【算法】求数组中某两个数的和为目标值
查看>>
如何高效学习动态规划?
查看>>
动态规划法(六)鸡蛋掉落问题(一)
查看>>
LeetCode 887.鸡蛋掉落(C++)
查看>>
奇异值分解(SVD)的原理详解及推导
查看>>
算法数据结构 思维导图学习系列(1)- 数据结构 8种数据结构 数组(Array)链表(Linked List)队列(Queue)栈(Stack)树(Tree)散列表(Hash)堆(Heap)图
查看>>
【机器学习】机器学习系统SysML 阅读表
查看>>
最小费用最大流 修改的dijkstra + Ford-Fulksonff算法
查看>>
最小费用流 Bellman-Ford与Dijkstra 模板
查看>>
实现高性能纠删码引擎 | 纠删码技术详解(下)
查看>>
scala(1)----windows环境下安装scala以及idea开发环境下配置scala
查看>>
zookeeper(3)---zookeeper API的简单使用(增删改查操作)
查看>>
zookeeper(4)---监听器Watcher
查看>>
zookeeper(2)---shell操作
查看>>
mapReduce(3)---入门示例WordCount
查看>>