Linux高级文件操作 -2

用poll实现多路传输

系统调用poll(), 允许进程在多个文件描述符之间同时阻塞。
进程不再不断地检查每个它所关心的文件描述符,而是通过一个系统调用来指定读取或者写入哪个文件描述符。当有一个或者多个文件有数据可以读取或者可以写入时,poll()调用返回,应用程序就可以读写这些文件描述符而不用担心阻塞。
一旦应用程序处理了这些文件,进程就可以发起另一个poll()调用,一直阻塞,直到有一个文件做好了被读取或者写入的准备。

poll()系统调用:

  #include <poll.h>
  int poll(struct pollfd *fds, nfds_t nfds, int timeout);

nfds指定了第一个参数所指向的数组中的元素数目;
timeout指定了poll()用多长时间来等待一个事件发生,如果是0被当做超时,poll()系统调用将永远超时(即永远轮询下去)。

第一个参数fds描述了哪些文件描述符以及哪种类型的I/O需要被监控,它是一个指向pollfd的结构的数组指针:

           struct pollfd {
               int   fd;         /* file descriptor */
               short events;     /* requested events */
               short revents;    /* returned events */
           };

The caller should specify the number of items in the fds array in nfds.

The field fd contains a file descriptor for an open file. If this field is negative, then the corresponding events field is ignored and the revents field returns zero. (This provides an easy way of ignoring a file descriptor for a single poll() call: simply negate the fd field.)

The field events is an input parameter, a bit mask specifying the events the application is interested in for the file descriptor fd. If this field is specified as zero, then all events are ignored for fd and revents returns zero.

The field revents is an output parameter, filled by the kernel with the events that actually occurred. The bits returned in revents can include any of those specified in events, or one of the values POLLERR, POLLHUP, or POLLNVAL. (These three bits are meaningless in the events field, and will be set in the revents field whenever the corresponding condition is true.)

If none of the events requested (and no error) has occurred for any of the file descriptors, then poll() blocks until one of the events occurs.

The timeout argument specifies the number of milliseconds that poll() should block waiting for a file descriptor to become ready. This interval will be rounded up to the system clock granularity, and kernel scheduling delays mean that the blocking interval may overrun by a small amount. Specifying a negative value in timeout means an infinite timeout. Specifying a timeout of zero causes poll() to return immediately, even if no file descriptors are ready.

The bits that may be set/returned in events and revents are defined in poll.h:

POLLIN There is data to read.
POLLPRI There is urgent data to read (e.g., out-of-band data on TCP socket; pseudoterminal master in packet mode has seen state change in slave).
POLLOUT Writing now will not block.
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.

有一些位由内核在revents中设置,但对于events没有意义:
POLLERR Error condition (output only). 这个时候errno被设置适当的值。
POLLHUP Hang up (output only).
POLLNVAL Invalid request: fd not open (output only).

如果超时poll()调用返回0,如果发生了错误就返回-1(例如fds不是一个合法的指针,或者文件本身的错误使得POLLERR被设置)。如果正确,则返回一个正整数,返回用非零的revents成员描述文件数量。

还是“Linux高级文件操作 -1”中描述的多路输入问题,当poll()调用返回的时候,就可以直到一个管道数据已经准备好可以被读,或者是一个管道已经被关闭。
然后通过检查这两个文件描述符对应的revents成员决定采取哪种行动,在行动完成后又回到poll()调用。
所以用poll模式绝大多数时间都阻塞在了poll()调用,而不是连续不断地检查使用了非阻塞I/O的文件描述符,这样就很大成都上降低了系统负载。

/* mpx-poll.c - Displays input from two pipes using \codefn{poll()} */

#include <fcntl.h>
#include <stdio.h>
#include <sys/poll.h>
#include <unistd.h>

int main(void) {
    struct pollfd fds[2];
    char buf[4096];
    int i, rc;

    /* open both pipes */
    if ((fds[0].fd = open("p1", O_RDONLY | O_NONBLOCK)) < 0) {
        perror("open p1");
        return 1;
    }

    if ((fds[1].fd = open("p2", O_RDONLY | O_NONBLOCK)) < 0) {
        perror("open p2");
        return 1;
    }

    /* start off reading from both file descriptors */
    fds[0].events = POLLIN;
    fds[1].events = POLLIN;

    /* while we're watching one of fds[0] or fds[1] */
    while (fds[0].events || fds[1].events) {
        if (poll(fds, 2, 0) < 0) {
            perror("poll");
            return 1;
        } 

        /* check to see which file descriptors are ready to be
           read from */
        for (i = 0; i < 2; i++) {
            if (fds[i].revents) {
                /* fds[i] is ready for reading, go ahead... */
                rc = read(fds[i].fd, buf, sizeof(buf) - 1);
                if (rc < 0) {
                    perror("read");
                    return 1;
                } else if (!rc) {
                    /* this pipe has been closed, don't try
                       to read from it again */
                    fds[i].events = 0;
                } else {
                    buf[rc] = '\0';
                    printf("read: %s", buf);
                }
            }
        } 
    }

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值