概述
在linux的IO多路复用中有水平触发,边缘触发两种模式,这两种模式的区别如下:
水平触发:如果文件描述符已经就绪可以非阻塞的执行IO操作了,此时会触发通知.允许在任意时刻重复检测IO的状态,没有必要每次描述符就绪后尽可能多的执行IO.select,poll就属于水平触发.
边缘触发:如果文件描述符自上次状态改变后有新的IO活动到来,此时会触发通知.在收到一个IO事件通知后要尽可能多的执行IO操作,因为如果在一次通知中没有执行完IO那么就需要等到下一次新的IO活动到来才能获取到就绪的描述符.信号驱动式IO就属于边缘触发.
epoll既可以采用水平触发,也可以采用边缘触发.
大家可能还不能完全了解这两种模式的区别,我们可以举例说明:一个管道收到了1kb的数据,epoll会立即返回,此时读了512字节数据,然后再次调用epoll.这时如果是水平触发的,epoll会立即返回,因为有数据准备好了.如果是边缘触发的不会立即返回,因为此时虽然有数据可读但是已经触发了一次通知,在这次通知到现在还没有新的数据到来,直到有新的数据到来epoll才会返回,此时老的数据和新的数据都可以读取到(当然是需要这次你尽可能的多读取).
下面我们还从电子的角度来解释一下:
水平触发:也就是只有高电平(1)或低电平(0)时才触发通知,只要在这两种状态就能得到通知.上面提到的只要有数据可读(描述符就绪)那么水平触发的epoll就立即返回.
边缘触发:只有电平发生变化(高电平到低电平,或者低电平到高电平)的时候才触发通知.上面提到即使有数据可读,但是没有新的IO活动到来,epoll也不会立即返回.
/*************************************************************************
> File Name: t_select.c
> Author: liuxingen
> Mail: liuxingen@nsfocus.com
> Created Time: 2014年08月11日 星期一 21时22分32秒
************************************************************************/
#include<stdio.h>
#include<unistd.h>
#include<sys/types.h>
#include<sys/time.h>
#include<sys/select.h>
#include<string.h>
#include<errno.h>
int main(int argc, char *argv[])
{
struct timeval timeout;
char buf[10];
fd_set readfds;
int nread, nfds, ready, fd;
while(1)
{
timeout.tv_sec = 20L;
timeout.tv_usec = 0;
fd = 0; //stdin
nfds = fd + 1;
FD_ZERO(&readfds);
FD_SET(fd, &readfds);
ready = select(nfds, &readfds, NULL, NULL, &timeout);
if(ready == -1 && errno == EINTR)
{
continue;
}else if(ready == -1)
{
fprintf(stderr, "select error:%sn", strerror(errno));
}
for(fd = 0; fd < nfds; fd++)
{
if(FD_ISSET(fd, &readfds))
{
nread = read(fd, buf, 9);
buf[nread] = '