【发布时间】:2011-09-07 13:08:10
【问题描述】:
我使用 fork() 创建了两个进程。子进程正在生成并将可变数量的数据(数组字符)连续写入管道。父进程从管道中读取数据并将接收到的数据打印到标准输出。
代码很简单:
switch (fork()) {
case -1:
exit (1);
break;
case 0:
close(fd[0]);
generate_data(fd[1]);
break;
default:
close(fd[1]);
while(1) {
n = read(fd[0], readbuffer, sizeof(readbuffer));
readbuffer[n] = 0;
if (n > 0)
printf ("read: %s\n", readbuffer);
else
exit(1);
}
break;
}
generate_data(int) 遍历一个列表,将每个元素(字符串)写入作为参数给出的文件描述符(在这种情况下是管道的写入端):
void generate_data(int fd)
{
node_t node* = list;
while (node != NULL) {
write(fd, node->data, strlen(node->data)+1);
node = node->next();
}
}
这里的问题是输出总是不可预测的:当另一个进程正在处理最后一个read时,子进程将数据写入管道,所以当它再次调用读取时,其余数据不再存在.
根据man 2 pipe,这不应该发生:
写入管道写入端的数据由 内核,直到它从管道的读取端读取。
获取 10 个元素的列表,一些输出示例:
示例 1:
read: element_4
read: element_8
read: element_9
示例 2:
read: element_7
read: element_8
read: element_9
read: element_10
示例 3:
read: element_2
read: element_8
有人知道这里发生了什么吗?
【问题讨论】:
-
不是没有显示写作的代码,也许还有一些示例输出。
-
到底是什么问题?次要 nitpick:read() 不读取以 null 结尾的字符串。您的 %s 格式需要一个以 nul 结尾的字符串。也许你应该添加“readbuffer[n] = 0;”阅读后,给予足够的空间。
-
感谢 cmets。我刚刚用更多信息编辑了这个问题。
-
仔细阅读我的答案——它准确地解释了问题所在,并且您上面的代码证实了这一点。
generate_data正在通过管道发送多个以 0 结尾的字符串;printf只是打印第一个。在generate_data中用换行符替换零,或者在阅读代码中解析它们。但关键是printf忽略了你给它的大部分内容,因为它在第一个 0 字节处停止打印。