poll, ppoll - wait for some event on a file descriptor
man page: http://man7.org/linux/man-pages/man2/poll.2.html
poll 是一种多路复用的IO机制。使用 poll 可以监听多个文件描述符,一但某个文件描述符就绪(一般是读就绪或者写就绪),能够通知程序进行响应的读写操作。
poll 本质是一种同步IO,因为需要在读写事件就绪后自己负责读写,也就是说这个读写过程是阻塞的,而异步IO则无需自己负责读写,异步IO的实现会负责把数据从内核拷贝到用户空间。
#include <poll.h> int poll(struct pollfd *fds, nfds_t nfds, int timeout); /** * 由于 poll 是监听多个文件描述符,所以 fds 传递的是数组地址 * nfds 指定监听的文件描述符个数 * timeout 超时时间,单位是 milliseconds * * 因为 poll 是同步 IO,那么 poll 必然是带阻塞的,带阻塞的函数,必然要设置超时时间,防止死等却等不到的情况。 */
struct pollfd { int fd; /* file descriptor */ short events; /* requested events */ short revents; /* returned events */ }; /** * fd : 是要监听的文件描述符 * events : 要监听的事件 * revents: 实际发生的事件 */
pollfd 没有最大数量的限制,但是数量过大后性能会下降。当然,随着pollfd的个数增加,poll 函数返回后,用户继续遍历 poll 数组也会更加耗时。
/* 常用参数说明 */ POLLIN There is data to read. POLLPRI There is some exceptional condition on the file descriptor. Possibilities include: * There is out-of-band data on a TCP socket (see tcp(7)). * A pseudoterminal master in packet mode has seen a state change on the slave (see ioctl_tty(2)). * A cgroup.events file has been modified (see cgroups(7)). POLLOUT Writing is now possible, though a write larger that the avail‐ able space in a socket or pipe will still block (unless O_NON‐ BLOCK is set). POLLRDHUP (since Linux 2.6.17) Stream socket peer closed connection, or shut down writing half of connection. The _GNU_SOURCE feature test macro must be defined (before including any header files) in order to obtain this definition. POLLERR Error condition (only returned in revents; ignored in events). This bit is also set for a file descriptor referring to the write end of a pipe when the read end has been closed. POLLHUP Hang up (only returned in revents; ignored in events). Note that when reading from a channel such as a pipe or a stream socket, this event merely indicates that the peer closed its end of the channel. Subsequent reads from the channel will return 0 (end of file) only after all outstanding data in the channel has been consumed. POLLNVAL Invalid request: fd not open (only returned in revents; ignored in events). When compiling with _XOPEN_SOURCE defined, one also has the follow‐ ing, which convey no further information beyond the bits listed above: POLLRDNORM Equivalent to POLLIN. POLLRDBAND Priority band data can be read (generally unused on Linux). POLLWRNORM Equivalent to POLLOUT. POLLWRBAND Priority data may be written. Linux also knows about, but does not use POLLMSG.
可以对照英文和中文翻译进行深入理解:http://www.cnblogs.com/alyssaCui/archive/2013/04/01/2993886.html
不难理解,再贴一个示例demo:
#include <string.h> #include <stdio.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <errno.h> #include <poll.h> #include <unistd.h> #define W_DATA "howaylee" int main(int argc, char* argv[]) { int ret = -1; int fd1 = -1; int fd2 = -1; char r_buf[12] = {0}; struct pollfd fds[2] = {0}; // open fd1 fd1 = open(argv[1], O_RDWR|O_CREAT, S_IRWXU); if (-1 == fd1) { perror("open fd1 failed: "); return -1; } // write fd1 ret = write(fd1, W_DATA, sizeof(W_DATA)); if (-1 == ret) { perror("write fd1 failed: "); goto _OUT; } // lseek fd1 head ret = lseek(fd1, 0, SEEK_SET); if (-1 == ret) { perror("lseek fd1 failed: "); goto _OUT; } // open fd2 fd2 = open(argv[2], O_RDWR|O_CREAT, S_IRWXU); if (-1 == fd2) { perror("open fd2 failed: "); return -1; } /* 阻塞,等待程序读写操作 */ while (1) { // 初始化 pollfd fds[0].fd = fd1; // 可读 fds[0].events = POLLIN; fds[1].fd = fd2; // 可写 fds[1].events = POLLOUT; // poll ret = poll(fds, sizeof(fds)/sizeof(fds[0]), -1); if (-1 == ret) { perror("poll failed: "); goto _OUT; } // read fd1 if (fds[0].revents & POLLIN) { // 清空缓存 memset(r_buf, 0, sizeof(r_buf)); ret = read(fd1, r_buf, sizeof(r_buf)); if (-1 == ret) { perror("poll read failed: "); goto _OUT; } // printf("read = %s\\n", r_buf); } // write fd2 if (fds[1].revents & POLLOUT) { ret = write(fd2, r_buf, sizeof(r_buf)); if (-1 == ret) { perror("poll write failed: "); goto _OUT; } printf("write = %s\\n", r_buf); } } //close fd1 fd2 close(fd1); close(fd2); _OUT: return ret; }
asdf