概述
poll() 系统调用是System V 的I/O多路复用的解决方案。它解决了一些 select() 的不足,不过 select() 还是被频繁的使用(还是出于习惯或可移植性的考虑)。
Poll()
#include <poll.h>
int poll(struct pollfd *fds, nfds_t nfds, int timeout);
select() 使用了基于文件描述符的三位掩码的解决方案,其效率不高;和它不同,poll() 使用了有 ndfs 个 pollfd 结构体构成的数组,fds 指针指向该数组。pollfd 结构体定义如下:
#include <poll.h>
struct pollfd {
int fd; /* file descriptor */
short events; /* requested events to watch */
short revents; /* returned events witnessed */
};
每个 pollfd 结构体指定一个被监视的文件描述符。可以给 poll() 传递多个 pollfd 结构体,使它能够监视多个文件描述符。每个结构体的 events 变量是要监视的文件描述符的事件的位掩码。用户可以设置该变量。 revents 变量是该文件描述符的结果事件的掩码。内核在返回时设置 revents 变量。events 变量中请求的所有事件都可能在 revents 变量中返回。以下是合法的 events 变量:
POLLIN 有数据可读
POLLRDNORM 有普通数据可读
POLLRDBAND 有优先数据可读
POLLPRI 有高优先级数据可读
POLLOUT 写操作不会阻塞
POLLWRNORM 写普通数据不会阻塞
POLLBAND 写优先数据不会阻塞
POLLMSG 有SIGPOLL 消息可用
此外,revents 变量可能会返回如下事件:
POLLER 给定的文件描述符出现错误
POLLHUP 给定的文件描述符有挂起事件
POLLNVAL 给定的文件描述符非法
对于 events 变量,这些事件没有意义,events 参数不要传递这些变量,它们会在 revents 变量中返回。 poll() 和 select() 不同,不需要显示请求异常报告。
POLLIN | POLLPRI 等价于 select() 的读事件,而 POLLOUT | POLLWRBAND 等价于 select() 的写事件。POLLIN 等价于 POLLRDNORM | POLLRDBAND, 而 POLLOUT 等价于 POLLWRNORM。
举个例子,要监视某个文件描述符是否可读写,需要把 events 设置成 POLLIN | POLLOUT 。返回时,会检查 revents 中是否有相应的标志位。如果设置了 POLLIN, 文件描述符可非阻塞读;如果设置了POLLOUT,文件描述符可非阻塞写。标志位并不是相互排斥的;可以同时设置,表示可以在该文件描述符上读写,而且都不会阻塞。
timeout 参数指定要等待的时间长度,单位是毫秒,不论是否有 I/O 就绪, poll() 调用都会返回。如果 timeout 值为负数,表示永远等待; timeout 为 0 表示 poll() 调用立即返回,并给出所有 I/O 未就绪的文件描述符列表,不会等待更多事件。在这种情况下,poll() 调用如同其名,轮询一次后立即返回。
返回值和错误码
poll() 示例
#include <stdio.h>
#include <unistd.h>
#include <poll.h>
#define TIMEOUT 5 /* poll timeout, in seconds */
int main(void)
{
struct pollfd fds[2];
int ret;
/* watch stdin for input */
fds[0].fd = STDIN_FILENO;
fds[0].events = POLLIN;
/* watch stdout for ability to write (almost always true) */
fds[1].fd = STDOUT_FILENO;
fds[1].events = POLLOUT;
/* All set, block! */
ret = poll(fds, 2, TIMEOUT * 1000);
if (ret == -1) {
perror("poll");
return 1;
}
if (!ret) {
printf("%d seconds elapsed.\n", TIMEOUT);
return 0;
}
if (fds[0].revents & POLLIN) {
printf("stdin is readable.\n");
}
if (fds[1].revents & POLLOUT) {
printf("stdout is writable.\n");
}
return 0;
}
stdin is readable.
stdout is writable.