【发布时间】:2016-01-02 16:46:52
【问题描述】:
我想在 C 语言中创建子编写器和父读取器之间的管道。 我认为我的父进程必须等待其子进程写入缓冲区才能读取它,但后来我想检查它,所以我编写了以下代码:
pipe(fd);
// ... checks for pipe
pid_t pid = fork();
// ... checks for fork
if (pid == 0) {
close(fd[0]);
// Long sleep hoping parent will terminate before the write()
sleep(10);
write(fd[1], "hello", strlen("hello") + 1);
close(fd[1]);
} else {
close(fd[1]);
read(fd[0], buf, sizeof(buf));
printf("received: %s\n", buf);
close(fd[0]);
}
return 0;
输出意外(或者不是?)received: hello。
如果我用 for (volatile int i = 0; i < some_big_int; ++i); 循环替换对 sleep() 的调用,则输出相同。
我不认为对read() 的调用会阻塞我的父进程,直到子进程在管道的另一端写入,但我无法解释这种行为。有什么提示吗?
【问题讨论】:
-
这是预期的操作:I.E.
read()块,将返回请求的总字节数被读取或遇到 eof。或某些错误事件和信号 -
我在
man 2 read中找不到这样说的地方:例如这句话似乎表明如果没有要读取的内容, read() 返回并且是非阻塞的:In the absence of any errors, or if read() does not check for errors, a read() with a count of 0 returns zero and has no other effects. -
当
read在流式fd(例如管道)上传递非零count时,它会阻塞直到至少有1 个字节可用,然后读取count那个时候可以。由于您write和close(并且写入小于PIPE_BUF),它会立即刷新整个字符串,因此当它解除阻塞时,它会立即获取您写入的所有内容。 -
read的count为 0 与您的情况无关,因为您没有通过count为 0。 -
write(fd[1], "hello", strlen("hello"));和read(fd[0], buf, sizeof(buf));不会 NUL 终止 buf,因为终止的 NUL 不会写入管道。此外,printf("received: %s\n", buffer);打印buffer的输出,而不是buf的内容。如果它试图打印buf的内容,发布的代码将调用未定义的行为。此外,失败的fork()调用将导致父进程在read()中永远阻塞。