Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/c/69.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
FIFO管道在select()中始终可读_C_Select_File Descriptor_Fifo - Fatal编程技术网

FIFO管道在select()中始终可读

FIFO管道在select()中始终可读,c,select,file-descriptor,fifo,C,Select,File Descriptor,Fifo,在C伪代码中: while (1) { fifo = open("fifo", O_RDONLY | O_NONBLOCK); fd_set read; FD_SET(fifo, &read); select(nfds, &read, NULL, NULL, NULL); } 进程在被select()触发时休眠,直到另一个进程写入fifo。之后,它将始终找到作为可读文件描述符的fifo 如何避免这种行为(即,在fifo被读取一次之后,如何使其在再

在C伪代码中:

while (1) {
    fifo = open("fifo", O_RDONLY | O_NONBLOCK);
    fd_set read;
    FD_SET(fifo, &read);
    select(nfds, &read, NULL, NULL, NULL);
}
进程在被
select()
触发时休眠,直到另一个进程写入
fifo
。之后,它将始终找到作为可读文件描述符的
fifo


如何避免这种行为(即,在
fifo
被读取一次之后,如何使其在再次写入之前被视为不可读?

简单的答案是读取直到
read()
返回
ewoodblock
(或
EAGAIN
),或者通过错误退出

除非您使用的操作系统(或运行时)有缺陷,否则您所说的根本不可能发生。否则你一定是做错了什么。例如,
select()

下面是一个简单的示例,说明了如何读取直到
read()
返回
ewoodblock
,以避免描述符处于可读状态(我已经在OS X上编译并测试了这个,并且基本上没有错误检查,但您应该知道):

/*
*使用select的FIFO示例。
*
*$mkfifo/tmp/fifo
*$clang-Wall-o测试。/test.c
*美元/测试&
*$echo'hello'>/tmp/fifo
*$echo“hello world”>/tmp/fifo
*$killall测试
*/
#包括
#包括
#包括
#包括
#包括
#包括
#包括
int main()
{
int-fd;
int n;
fd_集;
ssize_t字节;
大小\u t总字节数;
char-buf[1024];
fd=打开(“/tmp/fifo”,O|RDWR | O|非块);
如果(fd==-1){
佩罗(“公开”);
返回退出失败;
}
FD_零位(&set);
FD_集(FD,和集);
对于(;;){
n=选择(fd+1,&set,NULL,NULL,NULL);
如果(!n)
继续;
如果(n==-1){
佩罗(“选择”);
返回退出失败;
}
if(FD_设置(FD和设置)){
printf(“描述符%d已准备就绪。\n”,fd);
总字节数=0;
对于(;;){
字节=读取(fd、buf、sizeof(buf));
如果(字节>0){
总字节数+=(大小)字节数;
}否则{
if(errno==ewoldblock){
/*读完*/
printf(“已完成读取(%lu字节)\n)”,总字节数;
打破
}否则{
佩罗(“阅读”);
返回退出失败;
}
}
}
}
}
返回退出成功;
}
基本上,级别触发I/O意味着,如果有内容要读取,您会一直收到通知,即使您以前可能已经收到通知。相反,边缘触发I/O意味着每次新数据到达时,您只会收到一次通知,无论您是否读取它<代码>选择()
是一个级别触发的I/O接口


希望能有帮助。祝你好运

您以只读(O_RDONLY)方式打开该FIFO,每当FIFO没有写入程序时,读取端将收到一个
EOF

Select system call将在
EOF
上返回,并且对于您处理的每个
EOF
都将有一个新的
EOF
。这就是观察到的行为的原因


为了避免这种情况,请同时打开读写FIFO(O_RDWR)。这确保了FIFO上至少有一个写入程序,因此不会出现
EOF
,因此,除非有人向该FIFO写入,否则select不会返回。

那么,您希望发生什么?这是正确的答案,以防止运行无休止的EOL检测循环。这对我来说是正确的答案。不过,在我的例子中,我有它的一个小变体:管道总是返回2个fds-1用于读取,1用于写入;在我的例子中,我显式地关闭了写端(下面是C/S应用程序的代码示例)。因此,我遇到了同样的问题,因为EOF,读取端总是准备好读取。感谢Tipomg4小时来一直在寻找类似的东西。终于在这里找到了解决办法+1执行此操作时,我从不在fifo写入端的选择块中注册响应。它只是停滞不前。即使我将字符串从终端重定向到fifo,我仍然什么也得不到我认为另一个答案与这个答案相矛盾,并且是正确的<当阻塞
read
将返回时,code>select返回;如果没有人打开fifo进行写入,则
read
返回
0
(发送EOF信号)。您的示例程序从不这样做,因为它有fifo,可以自己编写。
/*
 * FIFO example using select.
 *
 * $ mkfifo /tmp/fifo
 * $ clang -Wall -o test ./test.c
 * $ ./test &
 * $ echo 'hello' > /tmp/fifo
 * $ echo 'hello world' > /tmp/fifo
 * $ killall test
 */

#include <sys/types.h>
#include <sys/select.h>
#include <errno.h>
#include <stdlib.h>
#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>

int main()
{
    int fd;
    int n;
    fd_set set;
    ssize_t bytes;
    size_t total_bytes;
    char buf[1024];

    fd = open("/tmp/fifo", O_RDWR | O_NONBLOCK);
    if (fd == -1) {
        perror("open");
        return EXIT_FAILURE;
    }

    FD_ZERO(&set);
    FD_SET(fd, &set);

    for (;;) {
        n = select(fd+1, &set, NULL, NULL, NULL);
        if (!n)
            continue;
        if (n == -1) {
            perror("select");
            return EXIT_FAILURE;
        }
        if (FD_ISSET(fd, &set)) {
            printf("Descriptor %d is ready.\n", fd);
            total_bytes = 0;
            for (;;) {
                bytes = read(fd, buf, sizeof(buf));
                if (bytes > 0) {
                    total_bytes += (size_t)bytes;
                } else {
                    if (errno == EWOULDBLOCK) {
                        /* Done reading */
                        printf("done reading (%lu bytes)\n", total_bytes);
                        break;
                    } else {
                        perror("read");
                        return EXIT_FAILURE;
                    }
                }
            }
        }
    }

    return EXIT_SUCCESS;
}