2016-01-05 29 views
1

我正在做一些实验来了解命名管道。这是我的理解,操作系统将阻止写入命名管道的程序,直到另一个程序从命名管道读取。所以我写了两个程序,startloopreadbytestartloop创建一个FIFO,并不断写入它与客户的每个读取(readbyte):运行时为什么在没有人阅读之后继续写入命名管道?

#include <stdio.h> 
#include <stdlib.h> 
#include <fcntl.h> 
#include <unistd.h> 
#include <sys/stat.h> 

int main(int argc, char *argv[]) { 
    const char num = 123; 
    mkfifo("fifo", S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP); 
    int fd = open("fifo", O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); 
    while (1) { 
     printf("loop_start\n"); 
     write(fd, &num, sizeof(num)); 
    } 
    close(fd); 
    return 0; 
} 

readbyte从FIFO中读取一个字节:

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

int main(int argc, char *argv[]) { 
    char num; 
    int fd; 
    if ((fd = open(argv[1], O_RDONLY, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)) == -1) { 
     perror("Cannot open input file\n"); exit(1); 
    } 

    read(fd, &num, sizeof(num)); 
    printf("%d\n", num); 
    close(fd); 
    return 0; 
} 

readbyte打印数量按预期时在“先进先出”运行:

hostname:dir username$ ./readbyte fifo 
65 

如我所料,loopstart直到我读不打印任何东西从与fifo readbyte。但是,当它变为畅通时,它会多次写入“fifo”,而不是立即暂停。为什么是这样?

hostname:dir username$ ./startloop 
loop_start 
loop_start 
loop_start 
loop_start 
loop_start 
loop_start 
loop_start 
loop_start 
loop_start 
loop_start 
loop_start 
loop_start 
loop_start 
loop_start 
loop_start 
loop_start 
loop_start 
loop_start 
loop_start 
loop_start 
+3

你怎么知道'write()'调用成功?你没有检查它的返回值。 –

+0

@Andrew Henle - 我知道它至少能以某种方式成功,因为'readbyte'能够打印出写入的内容。我确实有一个错误检查的版本 - 尽管如此,我删除了所有这些使帖子更短的文章。如果您认为这是问题,我可以将其添加回来。 – watkipet

+1

您的循环继续的事实意味着'write()'不*阻止*,不是*成功*。有很大的差异。如果您不知道发生了什么并希望获得帮助,则发布的数据越多,获得的帮助就越好。在这种情况下,发出一个循环计数器以及来自'write()'的返回值会比简单的“loop_start”好很多。这是一个容易解决的问题 - 解决更难的问题将需要额外的信息。 –

回答

3

“这是我的理解是,OS将阻止写入命名管道到另一个程序从命名管道读取的程序。”

这种理解是不正确的。除非管道/ FIFO已满,否则write不会阻塞。从pipe manul

管道的容量有限。如果管道已满,则写入(2) 将会阻塞或失败,具体取决于O_NONBLOCK标志是否设置为 (请参见下文)。

至于为什么第一个write似乎阻止 - 它实际上并没有。这是阻止的open。从fifo manaul

的FIFO必须在两端(读,写)数据 可以传递之前打开。通常情况下,打开FIFO模块,直到另一端 也被打开。

更新:其实上面第一个是write。但是可能有更多的解释。一旦readbyte程序关闭了fifo,后续的write调用应该开始失败。

+0

一旦阅读器关闭fifo,只有在'SIGPIPE'被忽略的情况下,写入调用才会失败并显示'EPIPE'。由于默认情况下信号不会被忽略,并且默认操作是终止进程,所以可以预期几次写入成功,直到管道关闭,然后进程终止。 – rici

+0

@rici谢谢并同意,这是一个有价值的说明。 – kaylum

1

测试写入结果

while (1) { 
     printf("loop_start\n"); 
    int ret = write(fd, &num, sizeof(num)); 
    if(ret == -1) 
    { 
     perror("error writing to fifo"); 
     exit(1); 
    } 
    }