您的位置:首页 > 运维架构 > Linux

linux系统编程手册 I/O复用

2016-07-15 11:31 357 查看

水平触发和边缘触发

水平触发(level-triggered,也被称为条件触发)LT:  只要满足条件,就触发一个事件(只要有数据没有被获取,内核就不断通知你)

边缘触发(edge-triggered)ET: 每当状态变化时,触发一个事件。

“举个读socket的例子,假定经过长时间的沉默后,现在来了100个字节,这时无论边缘触发和条件触发都会产生一个read ready notification通知应用程序可读。应用程序读了50个字节,然后重新调用api等待io事件。这时条件触发的api会因为还有50个字节可读,从而立即返回用户一个read ready notification。而边缘触发的api会因为可读这个状态没有发生变化而陷入长期等待。因此在使用边缘触发的api时,要注意每次都要读到socket返回EWOULDBLOCK为止,否则这个socket就算废了。

而在I/O复用的技术中:

1. select poll属于水平触发

2.信号驱动I/O属于边缘触发

3.epoll两种都有

对于边缘触发,最好将fd设置成非阻塞的,因为需要对文件描述符尽可能多的执行I/O,如果阻塞的,最终没有I/O可执行的话,I/O系统就阻塞了。

select poll当有大量文件描述符的话 性能较差。

信号驱动I/O

在信号驱动I/O中,当文件描述符有可执行I/O操作时,进程请求内核为自己发送一个信号。

下面我们来看下使用步骤:

1.发送信号默认SIGIO

2.设定文件描述符以及信号接收的进程ID

fcntl(fd, F_SETOWN, pid)

3.通过设定O_NONBLOCK标志设置非阻塞

4.通过打开O_ASYNC标志开启信号驱动I/O。

flags = fcntl(fd, F_GETFL);
fcntl(fd, F_SETFL, flags | O_ASYNC | O_NONBLOCK);

5.调用进程的其他任务了。当I/O操作准备就绪,内核会发送信号,然后调用在第一步中安装好的信号处理例程。

6.信号驱动提供的是边缘触发通知。这表示进程被通知I/O就绪,尽可能多执行I/O(读取字节)。如果是非阻塞的,需要循环执行I/O调用失败为止,错误码为EAGAIN EWOULDBLOCK。

我们可以使用如下方式获取信号接收的进程

id = fcntl(fd, F_GETOWN);

也可以通过如下方式,改变发送的信号

fcntl(fd, F_SETSIG, sig);



epoll机制

创建epoll实例 epoll_create

int epoll_create(int size);

size检查文件描述符的个数,在linux2.6.8版本后该参数忽略。可以使用epoll_create1函数,去掉了size参数,增加了一个flags参数,只有一个flag EPOLL_CLOEXEC。和open函数的O_CLOSEXEC一样。

epoll_ctl函数修改文件符epfd所代表epoll实例的兴趣列表。

EPOLL_CTL_ADD 增加fd

EPOLL_CTL_MOD 修改fd事件

EPOLL_CTL_DEL 删除fd

epoll_wait函数返回处于I/O就绪状态的fd。

如果timeout 为-1 一直阻塞,直到有fd事件

timeout为0,执行一次非阻塞

timeout大于0,阻塞timeout毫秒

epoll中events字段位掩码值

EPOLLIN 可读取非高优先级的数据

EPOLLPRI 可读取高优先级的数据

EPOLLRDHUP socket对端关闭

EPOLLOUT 普通数据可写

EPOLLET 采用边缘触发通知

EPOLLONESHOT 完成事件通知后禁止检查

EPOLLERR 有错误发生

EPOLLHUP 出现挂断

我们来说明下EPOLLONESHOT标志。设定这个标志代表这个fd处于非激活状态,下次激活的话需要epoll_ctl的EPOLL_CTL_MOD重新激活这个fd。


内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: