Linux的命名管道上的read()超时

问题描述 投票:1回答:2

假设我在Linux系统上创建了一个命名管道:

$ mkfifo my_pipe

接下来要做的是编写一个小的监视程序,该程序尝试从read()移至my_pipe,但过一会儿就会超时。在下面的伪代码中,我使用了虚构函数wait_for_avail(fd, timeout_ms)

int fd = open("my_pipe", O_RDONLY);
while (1) {
    //Fictional wait_for_avail(fd, timeout_ms). Is there a real function
    //that has this behaviour?
    int rc = wait_for_avail(fd, 500);
    if (rc == 1) {
        char buf[64];
        read(fd, buf, 64);
        //do something with buf
    } else {
        fprintf(stderr, "Timed out while reading from my_pipe\n");
        //do something else in the program
    }
}

我以为带有poll标志的POLLIN可能有用,但没有用。从我的简单试验中,我发现它只是等到另一个进程已经[[open]]命名管道进行写入(但没有可用的数据,即read()不会阻塞)。顺便说一下,由于某种原因,poll会忽略您的超时,并且似乎永远阻塞直到另一个进程打开管道为止。[我唯一想到的另一种解决方案是用open()O_NONBLOCK文件,并在我不断尝试以0字节为计数的read()时手动观察时间的流逝。

那里有更好的解决方案吗?

编辑:我在这里打开打开命名管道的过程受阻。但是,如果使用O_NONBLOCK标志,则文件将立即打开。在这一点上,poll()可用于等待(打开超时)等待打开管道的另一端以进行写入。

但是,这仍然具有为read()函数实现超时的行为。调用read()后,它似乎仍然会阻塞(即使使用O_NONBLOCK打开了管道)

假设我在Linux系统上创建了一个命名管道:$ mkfifo my_pipe接下来要做的是编写一个小的监视程序,该程序尝试从my_pipe读取(),但过一会儿就会超时。在...

c linux named-pipes
2个回答
1
投票
#include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <poll.h> #include <unistd.h> #include <stdio.h> #include <stdlib.h> int main(void) { while (1) { int fd = open("my_pipe", O_RDONLY | O_NONBLOCK); if (fd < 0) { perror("open"); return EXIT_FAILURE; } struct pollfd waiter = {.fd = fd, .events = POLLIN}; while (1) { // 10 second timeout switch (poll(&waiter, 1, 10 * 1000)) { case 0: puts("The fifo timed out."); break; case 1: if (waiter.revents & POLLIN) { char buffer[BUFSIZ]; ssize_t len = read(fd, buffer, sizeof buffer - 1); if (len < 0) { perror("read"); return EXIT_FAILURE; } buffer[len] = '\0'; printf("Read: %s\n", buffer); } else if (waiter.revents & POLLERR) { puts("Got a POLLERR"); return EXIT_FAILURE; } else if (waiter.revents & POLLHUP) { // Writer closed its end goto closed; } break; default: perror("poll"); return EXIT_FAILURE; } } closed: if (close(fd) < 0) { perror("close"); return EXIT_FAILURE; } } }

0
投票
该技术是在(阻止)read()调用之前设置计时器。然后,我们可以简单地检查read()的返回值以查看它是否由于超时而中断,是否发生了一般错误,是否达到了EOF或是否成功读取了数据。

只有一个障碍:您不能以非阻止模式打开文件;这会导致open()阻塞,直到另一个进程打开要写入的管道为止。但是,在我的应用程序中,这实际上是一个理想的功能。您也可以设置SIGALRM以对open()强制执行超时,或者在另一个线程中执行超时。

实际上,此技术应与任何其他系统调用一起使用,因此我可能会放一些帮助程序库,以使此模式更易于使用。

编辑

另外一件事:注册信号处理程序时不要使用SA_RESTART标志非常重要。否则,即使系统调用被信号中断,Linux也会在处理信号后重试。

© www.soinside.com 2019 - 2024. All rights reserved.