轮询操作select和poll

发布时间 2023-12-12 23:48:23作者: 七块蛋糕

select和poll系统调用最终会使设备驱动中的poll()函数被执行, Linux2.5.45内核还引入和epoll()即extended poll。

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

其中readfds、writefds、exceptfds分别是select()监视的读、写和异常处理的文件描述符集合,numfds的值表示select最多可以监视的fd的数量减一。只要readfds, writefds集中的文件分别变得可读和可写,select就会立即返回。

第一次对n个文件进行select的时候,若任何一个文件满足要求,select()就直接返回;第二次再进行select()的时候,没有文件满足读写要求,select()的进程阻塞且睡眠。同时调用select()的时候,每个驱动的poll()接口都会被调用到,实际执行select()的进程被挂到每个进程的等待队列上,可以被任何一个驱动唤醒。

 

相关操作用来设置,清除,判断文件描述符集合:

FD_ZERO(fd_set *set) 清除一个文件描述符集合

FD_SET(int fd, fd_set *set) 将一个文件描述符加入文件描述符集合中

FD_CLR(int fd, fd_set *set) 将一个文件描述符从文件描述符集合中清除

FD_ISSET(int fd, fd_set *set) 判断文件描述符是否置位


 

poll()的功能和实现原理与select()相类似,其函数原型位:
int poll(struct pollfd }fds, nfds_t nfds, int timeout);
当多路复用的文件数量庞大、IO流量频繁的时候,一般不太适合使用select()和poll(),此时宜使用epoll,它的最大好处是不会随着fd的数目增长而降低效率。
与epoll相关的用户空间编程接口包括:
int epoll_create(int size);

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

int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event);
epfd:epoll_create()的返回值
op: 表示动作
  EPOLL_CTL_ADD:注册新的fd到epfd中。
  EPOLL_CTL_MOD:修改已经注册的fd的监听事件。
  EPOLL_CTL_DEL:从epfd中删除一个fd。
fd: 需要监听的fd
event:告诉内核需要监听的事件类型


struct epoll_event {
__uint32_t events; /* Epoll events */
epoll_data_t data; /* User data variable */
};
events可以是以下几个宏的“或”:
  EPOLLIN:表示对应的文件描述符可以读。
  EPOLLOUT:表示对应的文件描述符可以写
  EPOLLPRI:表示对应的文件描述符有紧急的数据可读(这里应该表示的是有socket带外数据到
来)。
  EPOLLERR:表示对应的文件描述符发生错误。
  EPOLLHUP:表示对应的文件描述符被挂断。
  EPOLLET:将epoll设为边缘触发(Edge Triggered)模式,这是相对于水平触发(Level Triggered)来
说的。LT(Level Triggered)是缺省的工作方式,在LT情况下,内核告诉用户一个fd是否就绪了,之后用
户可以对这个就绪的fd进行I/O操作。但是如果用户不进行任何操作,该事件并不会丢失,而ET(Edge-
Triggered)是高速工作方式,在这种模式下,当fd从未就绪变为就绪时,内核通过epoll告诉用户,然后它
会假设用户知道fd已经就绪,并且不会再为那个fd发送更多的就绪通知。
  EPOLLONESHOT:意味着一次性监听,当监听完这次事件之后,如果还需要继续监听这个fd的话,
需要再次把这个fd加入到epoll队列里。

int epoll_wait(int epfd, struct epoll_event * events, int maxevents, int timeout);
等待事件的产生,其中events参数是输出参数,用来从内核得到事件的集合,maxevents告诉内核本次
最多收多少事件,maxevents的值不能大于创建epoll_create()时的size,参数timeout是超时时间(以毫秒
为单位,0意味着立即返回,-1意味着永久等待)。该函数的返回值是需要处理的事件数目,如返回0,则
表示已超时。