我是靠谱客的博主 虚拟烧鹅,这篇文章主要介绍IO多路复用技术中的水平触发(level trigger,LT)和边缘触发(edge trigger,ET)技术IO多路复用技术中的水平触发(level trigger,LT)和边缘触发(edge trigger,ET)技术,现在分享给大家,希望可以做个参考。
文章目录
- IO多路复用技术中的水平触发(level trigger,LT)和边缘触发(edge trigger,ET)技术
- 1. 什么是水平和边缘触发?
- 1.1 水平触发
- 1.1.1 读操作
- 1.1.2 写操作
- 1.2 边缘触发 (特指epoll模式下)
- 1.2.1 读操作
- 1.2.2 对于写操作
- 2 水平触发和边缘触发在 select poll epoll 中的应用
- 2.1 水平触发
- 2.1.1 select 水平触发具体示例:
- 2.1.2 poll 水平触发具体示例:
- 2.1.3 epoll 水平触发具体示例:
- 2.2 epoll中的边缘触发
IO多路复用技术中的水平触发(level trigger,LT)和边缘触发(edge trigger,ET)技术
在Linux中常用的IO复用技术有 select poll epoll 技术,select和poll只支持LT工作模式,epoll的默认的工作模式是LT模式。
1. 什么是水平和边缘触发?
1.1 水平触发
1.1.1 读操作
对于读操作,只要缓冲内容不为空,LT模式返回读就绪
1.1.2 写操作
对于写操作,只要缓冲区还不满,LT模式会返回写就绪
1.2 边缘触发 (特指epoll模式下)
1.2.1 读操作
- 当缓冲区由不可读变为可读的时候,即缓冲区由空变为不空的时候。
- 当有新数据到达时,即缓冲区中的待读数据变多的时候。
- 当缓冲区有数据可读,且应用进程对相应的描述符进行EPOLL_CTL_MOD 修改EPOLLIN事件时。
1.2.2 对于写操作
- 当缓冲区由不可写变为可写时。
- 当有旧数据被发送走,即缓冲区中的内容变少的时候。
- 当缓冲区有空间可写,且应用进程对相应的描述符进行EPOLL_CTL_MOD 修改EPOLLOUT事件时。
2 水平触发和边缘触发在 select poll epoll 中的应用
select和poll只支持LT工作模式,epoll的默认的工作模式是LT模式,这是select poll 和epoll区别之一。
2.1 水平触发
2.1.1 select 水平触发具体示例:
源码:
#include <sys/select.h>
#include <sys/time.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdio.h>
int main()
{
fd_set rd;
struct timeval tv;
int err;
FD_ZERO(&rd);
// 将键盘输入的作为读取的文件描述符,每次输入多个文件描述符
FD_SET(STDIN_FILENO,&rd);
tv.tv_sec = 5;
tv.tv_usec = 0;
char buffer[1024];
while (1)
{
select(1,&rd,NULL,NULL,&tv);
/*
每次输入多个字符,但是每次只读取一个字符,说明缓冲区还有别的东西,
在水平触发下会一直进行触发,直到缓冲区没有内容
*/
read(STDIN_FILENO, buffer, 1);
printf("select trigger n");
}
return 0;
}
编译执行如下:
# ./selsect
abcd // 输入字符 abcdn 所以会触发5次
select trigger
select trigger
select trigger
select trigger
select trigger
2.1.2 poll 水平触发具体示例:
源码:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <poll.h>
#include <unistd.h>
int main(void)
{
struct pollfd * pollFd;
char buffer[1024];
pollFd = malloc(sizeof(struct pollfd) * 1);
// 将键盘输入的作为读取的文件描述符,每次输入多个文件描述符
pollFd[0].fd = STDIN_FILENO;
pollFd[0].events = POLLIN;
int ready = 0;
while(1)
{
ready = poll(pollFd,1,-1);
printf("poll() trigger returned %dn",ready);
for(int i = 0;i < 1;i++)
{
if(pollFd[i].revents & POLLIN)
{
/*
每次输入多个字符,但是每次只读取一个字符,说明缓冲区还有别的东西,
在水平触发下会一直进行触发,直到缓冲区没有内容
*/
read(STDIN_FILENO, buffer, 1);
}
}
}
return 0;
}
编译运行如下:
root@wan:/wan/15.fly_in_coding/epoll# ./poll
abcd
poll() trigger returned 1
poll() trigger returned 1
poll() trigger returned 1
poll() trigger returned 1
poll() trigger returned 1
2.1.3 epoll 水平触发具体示例:
源码:
#include <unistd.h>
#include <stdio.h>
#include <sys/epoll.h>
int epoll_level_trigger()
{
int epfd, nfds;
char buffer[256];
struct epoll_event event, events[5];
epfd = epoll_create(1);
// 将键盘输入的作为读取的文件描述符,每次输入多个文件描述符
event.data.fd = STDIN_FILENO;
event.events = EPOLLIN; // 默认就是水平触发模式
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, buffer, 1);
printf("epoll level trigger n");
}
}
}
return 0;
}
int main()
{
return epoll_level_trigger();
}
编译运行如下:
# ./LT
abcd
epoll level trigger
epoll level trigger
epoll level trigger
epoll level trigger
epoll level trigger
2.2 epoll中的边缘触发
源码:
/*
源码中的三个函数分别代表上面介绍的边缘触发的三种条件
*/
#include <unistd.h>
#include <stdio.h>
#include <sys/epoll.h>
int epoll_edge_trigger_case1()
{
int epfd, nfds;
char buffer[1024];
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)
{
/*
每次输入多个字符,但是每次只读取一个字符,说明缓冲区还有别的东西,
但是在边缘触发下不会再次进行发。
如果应用进程对相应的描述符进行EPOLL_CTL_MOD 修改EPOLLIN事件时,则会进行再次触发
具体示例如下 epoll_edge_trigger_case2
*/
read(STDIN_FILENO, buffer, 1);
printf("epoll level trigger n");
}
}
}
return 0;
}
int epoll_edge_trigger_case2()
{
int epfd, nfds;
char buffer[1024];
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("epoll level trigger n");
}
}
}
return 0;
}
int epoll_edge_trigger_case3()
{
int epfd, nfds;
char buffer[1024];
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)
{
/*
每次输入多个字符,但是每次只读取一个字符,说明缓冲区还有别的东西,
在水平触发下会一直进行触发,直到缓冲区没有内容
*/
read(STDIN_FILENO, buffer, 1);
event.events = EPOLLIN | EPOLLET;
epoll_ctl(epfd, EPOLL_CTL_MOD, STDIN_FILENO, &event);
printf("epoll level trigger n");
}
}
}
return 0;
}
int main()
{
return epoll_edge_trigger_case1();
}
编译运行如下:
# ./LT1
abcd
epoll level trigger
# ./LT2
abcd
epoll level trigger
abcd
epoll level trigger
# ./LT3
abcd
epoll level trigger
epoll level trigger
epoll level trigger
epoll level trigger
epoll level trigger
最后
以上就是虚拟烧鹅最近收集整理的关于IO多路复用技术中的水平触发(level trigger,LT)和边缘触发(edge trigger,ET)技术IO多路复用技术中的水平触发(level trigger,LT)和边缘触发(edge trigger,ET)技术的全部内容,更多相关IO多路复用技术中的水平触发(level内容请搜索靠谱客的其他文章。
本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
发表评论 取消回复