linux io的轮询,Linux内核(七)轮询操作

轮询的概念与作用

在用户程序中,select()和poll()也是与设备阻塞和非阻塞访问相关的内容。

使用非阻塞IO的应用程序通常会使用select()和poll()系统调用查询是否可以对设备进行无阻塞的访问。

select()和poll()系统调用最终会使设备驱动中的poll()函数执行,在后续的Linux内核版本中还引入了epoll(),即扩展的poll()。

select()和poll()系统调用的本质是一样的,前者在BSD Unix中引入,后者在System V中引入。

应用程序中的轮询编程

应用程序中使用最广泛的是BSD Unix中引入的select()系统调用,原型如下:

//readfds文件集中的任何一个文件变得可读,select()将返回,同理writefds文件集中的任何一个文件变得可写,select()也返回

int select(

int numfds, //需要检查的号码最高的fd加1

fd_set *readfds, //被select()监视的读文件描述符的集合

fd_set *writefds, //被select()监视的写文件描述符的集合

fd_set *exceptfds, //被select()监视的异常处理文件描述符的集合

struct timeval *timeout //可以使select()在等待timeout时间后仍然没有文件描述符准备好则超时返回。

);

如下图所示,

第一次对n个文件进行select()的时候,若任何一个文件满足要求,select()就直接返回;

第二次再进行select()的时候,没有文件满足读写要求,select()的进程阻塞且睡眠。

由于调用select()的时候,每个驱动的poll()接口都会被调用到。实际上执行select()的进程被挂到了每个驱动的等待队列上,可以被任何一个驱动唤醒。如果FDn变得可读写,select()返回。

307eaf6c1ea4

image.jpeg

poll()的功能和实现原理与select()类似,其原型函数为:

int poll(struct pollfd *fds,nfds_t nfds,int timeout);

当多路复用的文件数量庞大、IO流量频繁的时候,一般不太适合使用select()和poll(),这种情况下select()和poll()表现较差,推荐使用epoll()。

使用epoll()最大的好处就是不会随着fd数目的增长而降低效率,select()则会随着fd数量增大性能明显下降。

相关接口:

int epoll_create(int size);

创建一个epoll()的句柄,size用来告诉内核要监听多少个fd,当创建好epoll()句柄时,它本身也会占用一个fd值,所以在使用完epoll()后,必须调用close()关闭。

告诉内核要监听什么类型的事件:

int epoll_ctl(int epfd, int op,int fd,struct_event *event);

第一个参数epfd是epoll_create()的返回值,

第二个参数表示动作,包含:

EPOLL_CTL_ADD:注册新的fd到epfd中

EPOLL_CTL_MOD:修改已经注册的fd的监听事件

EPOLL_CTL_DEL:从epfd中删除一个fd

第3个参数是需要监听的fd,

第4个参数是告诉内核需要监听的事件类型,struct_epoll_event结构如下:

struct_epoll_event{ __uint32_t events; //Epoll events epoll_data_t dara; //User data variable }

events可以是以下几个宏的”或“:

EPOLLIN:表示对应的文件描述符可以读

EPOLLOUT:表示对应的文件描述符可以写

EPOLLPRI:表示对应的文件描述符有紧急的数据可读

EPOLLERR:表示对应的文件描述符发生错误

EPOLLHUB:表示对应的文件描述符被挂断

EPOLLET:将epoll设为边缘触发(Edge Triggered)模式,这个是相对于水平触发(Level Triggered)来说的,LT是默认的工作方式

在LT情况下,内核告诉用户一个fd是否就绪了,之后用户可以对这个就绪的fd进行IO操作。但是如果用户不进行任何操作,该事件不会丢失

在ET的情况下,由于ET是一种高速工作模式,当fd从未就绪变成就绪时,内核通过epoll告诉用户,然后内核会假设用户知道fd已经就绪,并且不会再为那个fd发送更多的就绪通知。

EPOLLONESHOT:意味着一次监听,当监听完这次事件之后,如果还需要继续监听这个fd的话,需要再次把这个fd加入到epoll队列里

一般来说,当涉及的fd数量较少时,使用select是合适的;如果涉及的fd很多,如在大规模并发的服务器中监听许多socket的时候,则不太适合选用select,适合使用epoll。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值