C(Linux)中的管道问题
Posted
技术标签:
【中文标题】C(Linux)中的管道问题【英文标题】:Pipe trouble in C (Linux) 【发布时间】:2015-04-02 15:06:17 【问题描述】:我目前无法理解子级与其父级之间的非双工双向未命名管道通信。我正在尝试让最多十个孩子与超级父母进行交流。
目前我正在尝试让超级父母向每个孩子问好,然后孩子们向父母问好。最后,超级家长承认他收到了每个孩子的问候。
我在添加管道之前测试了叉子,它们工作正常,产生了正确数量的子代。所以我几乎可以肯定,问题出在我代码底部的两个 pipeCommunication() 方法中的一个(或两个)中。
当我运行程序时,它静止不动(好像在等待输入)。我预计它会卡在一个 while 循环中读取,但 我什至无法打印 main() 的第一行。
代码如下:
#include <sys/types.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/wait.h>
#include <string.h>
#include <stdbool.h>
int NUM_CHILDREN;
int ID;
// Create the pipes
void createPipes(int[], int[]);
// Wait for the children processes
void waitForChildren(int);
// The Child pipe communication method
void childPipeCommunication(int, int, int);
// The Parent pipe communication method
void parentPipeCommunication(int, int, int);
// MAIN FUNCTION
int main(int argc, char *argv[])
// NOT BEING PRINTED:
printf("Hello");
NUM_CHILDREN = argc - 1;
// The file descriptors for the pipes
int fd_childReads_ParentWrites[10][2]; // Parent should close 0, Child close 1
int fd_parentReads_ChildWrites[10][2]; // Child should close 0, Parent close 1
// Index of the child Array (0 to NUM_CHILDREN-1)
int user;
int pid;
int pidArray[10]; // Stores each of the child's process id's
// Fork the children and create the pipes
for(user = 0; user < NUM_CHILDREN; user++)
// Create the pipes
createPipes(fd_childReads_ParentWrites[user], fd_parentReads_ChildWrites[user]);
// Fork the children
pid = fork();
if (pid < 0) // Error occurred
printf("Fork Failed\n");
exit(1);
else if (pid == 0) // Child
break;
else if (pid) // Parent
pidArray[user] = pid;
if (pid == 0) // CHILD
// Close the appropriate pipe ends
close(fd_childReads_ParentWrites[user][1]);
close(fd_parentReads_ChildWrites[user][0]);
ID = getpid();
int n = 0;
// Enter pipe communication (user is the same as when it broke from the for loop)
childPipeCommunication(ID, fd_childReads_ParentWrites[user][0],
fd_parentReads_ChildWrites[user][1]);
// Finally, close the working child pipe ends
close(fd_childReads_ParentWrites[user][0]);
close(fd_parentReads_ChildWrites[user][1]);
else // PARENT
ID = getpid();
user = 0;
// Close the appropriate pipe ends
for (user = 0; user < NUM_CHILDREN; user++)
close(fd_childReads_ParentWrites[user][0]);
close(fd_parentReads_ChildWrites[user][1]);
// Go into Pipe Communication
for(user = 0; user < NUM_CHILDREN; user++)
parentPipeCommunication(pidArray[user], fd_parentReads_ChildWrites[user][0], fd_childReads_ParentWrites[user][1]);
// Wait for the children
waitForChildren();
// Finally, close the working parent pipe ends
for (user = 0; user < NUM_CHILDREN; user++)
close(fd_childReads_ParentWrites[user][1]);
close(fd_parentReads_ChildWrites[user][0]);
void createPipes(int fd1[2], int fd2[2])
if (pipe(fd1) < 0)
printf("Pipe creation error!\n");
exit(1);
if (pipe(fd2) < 0)
printf("Pipe creation error!\n");
exit(1);
void waitForChildren()
int user;
for (user = 0; user < NUM_CHILDREN; user++)
wait(NULL);
以下是管道通信的方法。
void childPipeCommunication(int childID, int fdReadFromParent, int fdWriteToParent)
char buf_ChildReads[80];
int n = 0;
while ((n = read(fdReadFromParent, buf_ChildReads, 80)) > 0)
buf_ChildReads[n] = 0;
// CASE: CHILD RECEIVES HELLO FROM PARENT
if(strcmp(buf_ChildReads, "Hi child.\n") == 0)
// Remove new line character
buf_ChildReads[--n] = 0;
// Acknowledge parent's hello and then send reply
printf("Child %d: Reveived message [%s] from parent\n", childID, buf_ChildReads);
write(fdWriteToParent, "Hello Parent\n", 13);
void parentPipeCommunication(int childID, int fdReadFromChild, int fdWriteToChild)
char buf_ParentReads[80];
int n = 0;
// Say hello to the child
write(fdWriteToChild, "Hi child\n", 9);
// Engage in communication with the child
while ((n = read(fdReadFromChild, buf_ParentReads, 80)) > 0)
buf_ParentReads[n] = 0;
// CASE: PARENT RECEIVES HELLO FROM CHILD
if(strcmp(buf_ParentReads, "Hello Parent\n") == 0)
printf("Parent: I have received response from child %d\n", childID);
如果有人能看一下我的代码并告诉我如何正确实现父子之间的通信,我将不胜感激。
【问题讨论】:
值 '10' 遍布整个代码,并且(隐式)期望参数的数量为 10。但是,代码中没有检查来确保该假设。完全忽略命令行参数会好得多(它们不用于计数以外的任何东西。)--或者-- 修改所有这些数组以使用计数。 @user,感谢您的帮助。但是,这只是代码的一部分。我还有很多关于这些值的内容,但我只想主要包括管道通信。 【参考方案1】:1) 问题:printf 未打印:
stdout
通常在 Unix 下是行缓冲的。尝试打印到stderr
(无缓冲),调用fflush(stdout)
,或显式打印"\n"
。
2) 问题:写 & strcmp
请注意,write(fd, "Hi child\n", 9)
没有尾随 '\0'
,但 strcmp 比较以零结尾的字符串。因此,您的子进程永远不会响应。
通过管道的双向 IPC 存在许多缺陷。见https://unix.stackexchange.com/questions/11946/how-big-is-the-pipe-buffer
【讨论】:
【参考方案2】:您将 NUM_CHILDREN 设置为命令行参数的数量。如果您未能提供任何参数,则它为零,不进入循环,未初始化 pid 并且未定义将采用底部的两条路径中的哪一条。两者都会挂起。
在没有从标准输入读取数据并且发生挂起的情况下使用 printf 时,您可能需要使用 fflush
来获取输出。
接下来,您的父母希望收到没有句号的消息,而您的孩子正在发送句号。
最后,父母和孩子都在循环,直到另一个关闭,所以来自第一个孩子的通信不会结束,以后的孩子也不会被处理。
【讨论】:
感谢有关 cmd 行参数的信息。我的代码中确实有验证,只是没有添加到这里,总会有 3 到 10 个孩子。反正那个时期肯定是有问题的,加了之后你是对的,其他小朋友就不交流了。您能否提供一个解决方案,说明如何与所有孩子保持持续沟通?或者类似的东西? 当孩子没有话要说的时候,这行不是退出循环吗?while ((n = read(fdReadFromChild, buf_ParentReads, 80)) > 0)
同样,当孩子从父母那里读取()时?
我想我知道如何绕过它。谢谢。
该行仅在另一端关闭管道时才退出。你需要一个条件/命令来触发它。以上是关于C(Linux)中的管道问题的主要内容,如果未能解决你的问题,请参考以下文章