1. 程式人生 > >多路複用IO--poll

多路複用IO--poll

多路複用IO–poll

poll定義

#include <poll.h>
int poll(struct pollfd fdarray[], nfds_t nfds, int timeout);

返回值:準備就緒的描述符數目:若超時,返回0;若出錯,返回-1

與select不同,poll不是為每個條件(可續性、可寫性和異常條件)構造一個描述符集,而是構造一個pollfd結構的陣列,每個陣列元素指定一個描述符編號以及我們對該描述符感興趣的條件。

struct pollfd {
  int fd;           /* file descriptor to check, or < 0 to ignore */
short events; /* events of interest on fd */ short revents; /* events that occurred on fd */ }

引數說明

(1)fdarray陣列中的元素數由nfds指定。

(2)應將每個陣列元素的events成員設定為下圖中所示值的一個或幾個,通過這些值告訴核心我們關心的是每個描述符的哪些事件。返回時,revents成員由核心設定,用於說明每個描述符發生了哪些事件。

標誌名 輸入至events? 從revents得到結果? 說明
POLLIN y y 可以不阻塞地讀高優先順序資料意外的資料(等效於POLLRDNORM|POLLRDBAND)
POLLRDNORM y y 可以不阻塞地讀普通資料
POLLRDBAND y y 可以不阻塞地讀優先順序資料
POLLPRI y y 可以不阻塞地讀高優先順序資料
POLLOUT y y 可以不阻塞地寫普通資料
POLLWRNORM y y 與POLLOUT相同
POLLWRBAND y y 可以不阻塞地寫優先順序資料
POLLERR y 已出錯
POLLHUP y 已結束通話
POLLNVAL y 描述符沒有引用一個開啟檔案

(3)poll的最後一個引數指定的是我們願意等待多長時間。

  • timeout == -1

    永遠等待。

  • timeout == 0

    不等待。測試所有描述符並立即返回。

  • timeout > 0

    等待timeout毫秒。當指定的描述符之一已準備好,或timeout到期時立即返回。如果timeout到期時還沒有一個描述符準備好,則返回值是0。

例項講解

下面已一個例子來演示poll的用法。

我們有兩個程式,poll.c和write_fifo.c。

poll.c中,我們迴圈監聽了兩個描述符,STDIN_FILENO標準輸入描述符和命名管道fd。不同的fd上有資料反饋,在顯示器上會列印不同的輸出。

write_fifo.c中,每隔5秒向命名管道fd寫入”this is for test”。

/**
 * poll.c
 * 演示poll的主要用法
 */

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <fcntl.h>
#include <poll.h>

#define fifo_filename "test_fifo"

int main(int argc, char *argv[])
{
    int ret;
    int fd;
    struct pollfd fds[2];

    ret = mkfifo(fifo_filename, 0666);
    if (ret != 0) {
        perror("mkfifo error");
    }

    fd = open(fifo_filename, O_RDWR);
    if (fd < 0) {
        perror("open error");
        exit(-1);
    }

    ret = 0;

    fds[0].fd = 0;
    fds[1].fd = fd;

    fds[0].events = POLLIN;
    fds[1].events = POLLIN;

    while (1) {
        ret = poll(fds, 2, -1);

        if (ret == -1) {
            perror("epoll_wait error");
        } else if (ret > 0) {
            char buf[100] = {0};

            if ((fds[0].revents & POLLIN) == POLLIN) {
                read(0, buf, sizeof(buf));
                printf("stdin buf = %s\n", buf);
            } else if ((fds[1].revents & POLLIN == POLLIN)) {
                read(fd, buf, sizeof(buf));
                printf("fifo buf = %s\n", buf);
            }
        } else if (ret == 0) {
            printf("time out\n");
        }
    }

    exit(0);
}
/**
 * write_fifo.c
 * 給命名管道傳送資訊
 */

#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
#include <fcntl.h>

#define fifo_filename "test_fifo"

int main(int argc, char *argv[])
{
    int ret = 0;
    int fd;

    ret = mkfifo(fifo_filename, 0666);
    if (ret != 0) {
        perror("mkfifo error");
    }

    fd = open(fifo_filename, O_RDWR);
    if (fd < 0) {
        perror("open error");
        exit(-1);
    }

    while (1) {
        char *str = "this is for test";
        write(fd, str, strlen(str));
        printf("after write to fifo\n");
        sleep(5);
    }

    exit(0);
}

編譯兩個程式

/myblog/myblog/source/poll# gcc poll.c -o poll
/myblog/source/poll# gcc write_fifo.c -o write_fifo

啟動poll程式,如下:

/myblog/source/poll# ./poll
fifo buf = this is for test
fifo buf = this is for test
fifo buf = this is for test
hello
stdin buf = hello

fifo buf = this is for test
fifo buf = this is for test
^C

啟動write_fifo程式,如下:

/myblog/source/poll# ./write_fifo
mkfifo error: File exists
after write to fifo
after write to fifo
after write to fifo
after write to fifo
after write to fifo
^C

從程式執行結果可以看出,當write_fifo不斷往命名管道寫入”this is for test”時,select監聽到命名管道fd已準備好,從fd上讀出資料並列印到顯示器上;當我們從標準輸入中打出hello時,select監聽到STDIN_FILENO(描述符為0)已準備好,從描述符0中讀出資料並列印到顯示器上。