以下是该计划:
int fd[2];
char buf1 [31];
int i;
char buf2;
pipe(fd);
if (fork() == 0) { // child
close(fd[1]); // close writing pipe
for(i = 0; i< 20; i++) {
read(fd[0], buf1, 30);
printf("%s\n", buf1);
}
close(fd[0]);
}
else { // parent
close(fd[0]); // close reading end
buf2 = 'a';
for (i = 0; i < 20; i++) {
write(fd[1], &buf2, sizeof(buf2));
}
close(fd[1]);
}
wait(NULL);
由于读取阻塞,如果没有任何内容,我们将首先写入管道。
我的问题是关于写功能。 for循环运行20次,每次我向管道写a
。经过20次迭代后,写入端的管道将包含aaaaaaaaaaaaaaaaaaaa
在孩子中,我将所有20 a's
读到buf1
,然后打印结果。
现在管道是空的,因为我们已经写过并阅读了我们写的内容?
由于这里还有一个for循环,我们再次阅读,但这一次,我认为管道是空的,所以没有什么可读的。所以我认为20次迭代后的最终输出就是
aaaaaaaaaaaaaaaaaaaa
但实际上就是这样:
aaaaaaaaaaaaaaaaaaaa
aaaaaaaaaaaaaaaaaaaa
aaaaaaaaaaaaaaaaaaaa
aaaaaaaaaaaaaaaaaaaa
aaaaaaaaaaaaaaaaaaaa
aaaaaaaaaaaaaaaaaaaa
aaaaaaaaaaaaaaaaaaaa
aaaaaaaaaaaaaaaaaaaa
aaaaaaaaaaaaaaaaaaaa
aaaaaaaaaaaaaaaaaaaa
aaaaaaaaaaaaaaaaaaaa
aaaaaaaaaaaaaaaaaaaa
aaaaaaaaaaaaaaaaaaaa
aaaaaaaaaaaaaaaaaaaa
aaaaaaaaaaaaaaaaaaaa
aaaaaaaaaaaaaaaaaaaa
aaaaaaaaaaaaaaaaaaaa
aaaaaaaaaaaaaaaaaaaa
aaaaaaaaaaaaaaaaaaaa
aaaaaaaaaaaaaaaaaaaa
为什么呢?我们读完后管道不是空的吗?
答案 0 :(得分:2)
你是正确的,如果孩子在父母写过任何东西之前调用read
,那么呼叫将会阻止;但是,在父关闭文件描述符后,情况不再如此,read
将返回0表示EOF。
read
调用不会清除缓冲区。操作系统成功读取零个字符,因此更改缓冲区的前0个字符。也就是说,它根本不会改变buf1
。因此,一旦所有数据都被读入缓冲区,printf
调用将始终执行相同的操作。
请注意,您无法保证获得此输出。孩子完全有可能在父母的一些但不是所有的write
来电之后运行,在这种情况下,它不会同时读取所有20个a
并打印更短的字符串。这就是为什么上面我说过printf
调用在读完所有数据后总是做同样的事情。要处理未写入所有数据的情况,应检查read
的返回值。如果它小于20,你没有将完整的字符串读入缓冲区(并且应该再次调用read
并使目标指针前进,这样就不会覆盖你的数据);如果它为零,那么你已到达文件结尾(写入结束);如果它是否定的则出现错误,您应该检查errno
来处理它。