5

我正在阅读 C 编程中的 poll 并构建了poll(2) 手册页上给出的应用程序。

这是示例:

#include<stdio.h>
#include <stropts.h>
#include <poll.h>
#include <fcntl.h>

int main() {

    struct pollfd fds[2];
    int timeout_msecs = -1;
    int ret;
    int i;

    /* Open STREAMS device. */
    fds[0].fd = open("/home/jeshwanth/mywork/poll/dev0", O_RDONLY);
    fds[1].fd = open("/home/jeshwanth/mywork/poll/dev1", O_RDONLY);
    fds[0].events = POLLOUT | POLLWRBAND;
    fds[1].events = POLLOUT | POLLWRBAND;

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

        if (ret > 0) {
            /* An event on one of the fds has occurred. */
            for (i = 0; i < 2; i++) {
                if (fds[i].revents != 0) {
                    /* Priority data may be written on device number i. */
                    printf(
                            "Priority Data may be written on device number %d POLLWRBAND\n",
                            i);

                }
                if (fds[i].revents = !0) {
                    /* Data may be written on device number i. */
                    printf("Data may be written on device number %d POLLOUT\n",
                            i);
                }
                if (fds[i].revents = !0) {
                    /* A hangup has occurred on device number i. */
                    printf("A hangup has occurred on device number %d\n", i);

                }
            }
        }
    }
    return 0;
}

注意:dev0 和 dev1 是普通文件。当我运行程序时,如果 dev0 和 dev1 中没有发生任何事件,则会显示该消息。但我期待当一些写入文件发生时,它才会显示消息。我错了吗?

4

3 回答 3

3

轮询它是否准备好输出并不意味着您会在某些输出发生时收到通知:这意味着您会在有可用的输出缓冲区空间时收到通知以便您可以输出(但您仍然应该检查输出函数的返回值. 缓冲区状态可能在轮询和输出之间发生了变化;始终检查返回值)。

于 2012-09-16T09:46:44.207 回答
2

最小 FIFO 命名管道示例

您将看不到常规文件的任何有趣内容,因为它们总是POLLIN立即给出:select() 如何等待常规文件描述符(非套接字)?

最简单的方法poll是使用命名管道,如下所示。这应该让您为他们的主要应用做好准备:套接字和设备文件。

来源如下。用法:

sudo mknod poll0.tmp p
sudo mknod poll1.tmp p
sudo chmod 666 poll*.tmp
./poll.out

在另一个外壳上:

printf a > poll0.tmp
printf b > poll1.tmp

输出:

loop
POLLIN i=0 n=1 buf=a
loop
POLLHUP i=0
loop
POLLIN i=1 n=1 buf=b
POLLHUP i=1
loop

所以请注意如何poll等待读取而不循环。

冷却器示例:

(while true; do date; sleep 1; done) > poll0.tmp &
(while true; do date; sleep 2; done) > poll1.tmp &

0每隔一秒和1每两秒写入一次,这显示了如何poll()同时处理两个输入,而不会相互拖延。

来源:

#define _XOPEN_SOURCE 700
#include <fcntl.h> /* creat, O_CREAT */
#include <poll.h> /* poll */
#include <stdio.h> /* printf, puts, snprintf */
#include <stdlib.h> /* EXIT_FAILURE, EXIT_SUCCESS */
#include <unistd.h> /* read */

int main(void) {
    enum { N = 2 };
    char buf[1024], path[1024];
    int fd, i, n;
    short revents;
    struct pollfd pfds[N];

    for (i = 0; i < N; ++i) {
        snprintf(path, sizeof(path), "poll%d.tmp", i);
        /* O_NONBLOCK is required or else the open blocks
         * until the other side of the pipe opens. */
        fd = open(path, O_RDONLY | O_NONBLOCK);
        if (fd == -1) {
            perror("open");
            exit(EXIT_FAILURE);
        }
        pfds[i].fd = fd;
        /* Only events in this mask will be listened to.
         * However, there are also some events that are unmaskable,
         * notably POLLHUP when pipe closes! */
        pfds[i].events = POLLIN;
    }
    while (1) {
        puts("loop");
        i = poll(pfds, N, -1);
        if (i == -1) {
            perror("poll");
            exit(EXIT_FAILURE);
        }
        for (i = 0; i < N; ++i) {
            revents = pfds[i].revents;
            if (revents & POLLIN) {
                n = read(pfds[i].fd, buf, sizeof(buf));
                printf("POLLIN i=%d n=%d buf=%.*s\n", i, n, n, buf);
            }
            if (revents & POLLHUP) {
                printf("POLLHUP i=%d\n", i);

                /* This happens when the other side closed.
                 * This event is only cleared when we close the reader. */

                /* poll won't set POLLHUP anymore once all fds are closed.
                 * Any futher polls on this will give the POLLNVAL event instead. */
                close(pfds[i].fd);

                /* negative fds are ignored. So if we negate an FD,
                 * we can both turn if off for a while, and turn it on
                 * later on by re-nagating it. */
                pfds[i].fd *= -1;
            }
        }
    }
}

编译:

gcc -o poll.out -std=c99 poll.c

在 Ubuntu 14.04 中测试。

GitHub 上游.

这些行:

close(pfds[i].fd);
pfds[i].fd *= -1;

是必需的,否则你会POLLHUP永远得到,另请参阅:如何使用 poll C 函数来观察 Linux 中的命名管道?

为了更有趣,创建一个实现pollfops 的 Linux 内核模块:如何在内核模块代码中添加轮询功能?

于 2017-05-23T06:46:18.340 回答
0

我会给你一个关于如何纠正它的提示。revents被解释为几个位标志。

/* check for priority write readiness */
if (fds[i].revents & POLLWRBAND) {
  printf("Priority Data may be written on device number %d POLLWRBAND\n", i);
}

/* check for write readiness */
if (fds[i].revents & POLLOUT) {
  printf("Data may be written on device number %d POLLOUT\n", i);
}

/* check for hang-up */
if (fds[i].revents & POLLHUP) {
  printf("A hangup has occurred on device number %d\n", i);
}
于 2012-09-16T06:16:56.897 回答