您的位置:首页 > 其它

IO复用

2017-03-20 18:11 127 查看
IO复用:使得程序能同时监听多个文件描述符

select:

select在一段指定的时间内,监听用户感兴趣的文件描述符的 读、写、异常事件。

select(int nfds,fd_set* readfds ,fd_set* writefds,fd_set* exceptfds,struct timeval* timeout);

当调用了select之后整个进程就会被block。同时kernel会监听select负责的所有的socket.如果

相关的时间就绪就会返回。

但是select只能处理 读、写、异常事件,不能处理更多的事件。

而且内核是对fd_set集合在线修改,下次调用不得不重置相应的集合。。。

poll:

int poll(struct pollfd* fds,....);

与select不同的是poll将 文件描述符和时间集合都定义在了 结构体中。并且注册事件和实际发生事件

被分开了。

struct pollfd
{
int fd;
short events;   //注册事件
short revents;   //实际发生事件
}

于是每次内核修改的是revents,无需重置pollfd了。

epoll:

epoll将用户关心的文件描述符放在内核的一个事件表中,从而无须每次重复传递。但需要一个额外的文件描述符

来标志内核中的时间表

epoll_create(int size)             //创建一个事件表
epoll_ctl()                          //给文件符指定操作类型(注册xxx上的xxx事件...)
epoll_wait()                         //等待事件


三种方法差异:

select和poll都只能工作在相对低效的LT模式中,epoll则能在ET模式中并支持EPOLLONESHOT。

select和poll采用的轮询的方式,每次调用都要扫描整个事件表O(n),而epoll采用的是回调,如果检测到

就绪的,回调函数就将对应时间插入内核就绪队列中,最后直接拷贝出来O(1)。

如果触发频繁,epoll的效率不一定高。所以epoll适合连接数量多,活动少的情况。

LT和ET:

1.LT(电平模式):

当epoll_wait检测到事件发生,程序可以不立即处理,再次调用还会出现此事件,直到事件被处理。

2.ET(边沿触发):

当epoll_wait检测到事件发生,程序必需立即处理,因为再次调用不会出现。

EPOLLONESHOT事件:

即便使用ET,一个事件还是可能被多次触发。

比如一个线程读取完某个socket上的数据并进行处理时,socket又出现新的数据可读。。。

此时另一个线程会被唤醒来处理这个。

如果希望任意时刻一个socket只被一个线程处理,可以使用epoll的EPOLLONESHOT

参考:

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