彻底学会使用epoll(二)——ET和LT的触发方式

ET与LT触发机制解析
本文详细对比了EPOLL中的边缘触发(ET)与水平触发(LT)模式下的读写操作触发条件。针对ET模式,文章阐述了读取操作在buffer状态变化时的唤醒条件,以及写操作在buffer空间可用时的唤醒条件。对于LT模式,则进一步解释了其在读写过程中更为宽松的触发条件。

分析了ETLT的实现方式,那么分析他们的触发方式就容易多了。我们通过实现分析知道LT模式下epoll_wait被唤醒可以通过两种方式(图中红线和蓝线),而ET模式只能通过一种方式(图中红线)。所以ET模式下能被唤醒的情况,LT模式下一定也能被唤醒。我们先来讨论特殊情况(ET模式),再来讨论一般情况(LT模式)。

2.1 ET

根据上一节对两种加入rdlist途径的分析,可以得出ET模式下被唤醒(返回就绪)的条件为:

对于读取操作:

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

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

另外补充一点:

(3) buffer中有数据可读(即buffer不空)且用户对相应fd进行epoll_mod IN事件(具体见下节内容)。

对于情况(1)(2)分别对应图1(a),1(b)

对于写操作:

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

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

另外补充一点:

(3) buffer中有可写空间(即buffer不满)且用户对相应fd进行epoll_mod OUT事件(具体见下节内容)。

对于情况(1)(2)分别对应图2(a),2(b)

   

                                    (a)                                                                                                       (b)

1 ET读触发的两种情况

2 LT写触发的两种情况

2.2 LT

LT模式下进程被唤醒(描述符就绪)的条件就简单多了,它包含ET模式的所有条件,也就是上述列出的六中读写被唤醒的条件都是用于LT模式。此外,还有更普通的情况LT可以被唤醒,而ET则不理会,这也是我们需要注意的情况。

对于读操作

buffer中有数据,且数据被读出一部分后buffer还不空的时候,即buffer中的内容减少的时候,LT模式返回读就绪。如下图所示。 

对于写操作

buffer不满,又写了一部分数据后扔然不满的的时候,即由于写操作的速度大于发送速度造成buffer中的内容增多的时候,LT模式会返回就绪。如下图所示。

注:pollselect都是LT模式。

epoll中,ET(边缘触发LT(水平触发)是两种不同的触发模式,它们决定了epoll_wait返回事件的时机。 1. **LT(水平触发)模式**: - LT模式是默认的模式。 - 在LT模式下,只要文件描述符上有事件发生,epoll_wait就会返回这些事件。 - 如果应用程序没有处理完这些事件,epoll_wait会在下一次调用时再次返回这些事件。 2. **ET(边缘触发)模式**: - ET模式需要显式地设置。 - 在ET模式下,只有在文件描述符的状态发生变化时,epoll_wait才会返回事件。 - 如果应用程序没有处理完这些事件,epoll_wait不会在下一次调用时再次返回这些事件。 ### 使用示例 #### LT模式 ```c #include <stdio.h> #include <stdlib.h> #include <sys/epoll.h> #include <unistd.h> #define MAX_EVENTS 10 int main() { int epoll_fd = epoll_create1(0); if (epoll_fd == -1) { perror("epoll_create1"); exit(EXIT_FAILURE); } struct epoll_event event; event.data.fd = STDIN_FILENO; event.events = EPOLLIN; if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, STDIN_FILENO, &event)) { perror("epoll_ctl"); exit(EXIT_FAILURE); } struct epoll_event events[MAX_EVENTS]; while (1) { int nfds = epoll_wait(epoll_fd, events, MAX_EVENTS, -1); if (nfds == -1) { perror("epoll_wait"); exit(EXIT_FAILURE); } for (int n = 0; n < nfds; ++n) { if (events[n].data.fd == STDIN_FILENO) { char buffer[1024]; int bytes_read = read(STDIN_FILENO, buffer, sizeof(buffer) - 1); if (bytes_read > 0) { buffer[bytes_read] = '\0'; printf("Read: %s\n", buffer); } } } } close(epoll_fd); return 0; } ``` #### ET模式 ```c #include <stdio.h> #include <stdlib.h> #include <sys/epoll.h> #include <unistd.h> #define MAX_EVENTS 10 int main() { int epoll_fd = epoll_create1(0); if (epoll_fd == -1) { perror("epoll_create1"); exit(EXIT_FAILURE); } struct epoll_event event; event.data.fd = STDIN_FILENO; event.events = EPOLLIN | EPOLLET; if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, STDIN_FILENO, &event)) { perror("epoll_ctl"); exit(EXIT_FAILURE); } struct epoll_event events[MAX_EVENTS]; while (1) { int nfds = epoll_wait(epoll_fd, events, MAX_EVENTS, -1); if (nfds == -1) { perror("epoll_wait"); exit(EXIT_FAILURE); } for (int n = 0; n < nfds; ++n) { if (events[n].data.fd == STDIN_FILENO) { char buffer[1024]; int bytes_read; while ((bytes_read = read(STDIN_FILENO, buffer, sizeof(buffer) - 1)) > 0) { buffer[bytes_read] = '\0'; printf("Read: %s\n", buffer); } } } } close(epoll_fd); return 0; } ``` ### 总结 - **LT模式**适用于大多数情况,编程简单,但可能会导致epoll_wait返回多次。 - **ET模式**适用于高并发场景,减少epoll_wait的调用次数,但需要确保一次性处理完所有事件。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值