epoll哪些触发模式_epoll的LT水平触发和ET边缘触发模式区别

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

a

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://blog.lucode.net/linux/epoll-tutorial.html

http://blog.chinaunix.net/uid-28541347-id-4285054.html

http://blog.chinaunix.net/uid-28541347-id-4288802.html

https://banu.com/blog/2/how-to-use-epoll-a-complete-example-in-c/

---------------------

作者:haozlee

来源:CSDN

原文:https://blog.csdn.net/lihao21/article/details/67631516

版权声明:本文为博主原创文章,转载请附上博文链接!

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值