C 中的管道问题 (Linux)
Pipe trouble in C (Linux)
我目前无法理解 non-duplex two-way children 和他们的 parent 之间的未命名管道通信。我正在尝试与超级 parent.
通信最多十个 children
目前我正在尝试让超级 parent 向每个 children 打招呼,然后 children 向 parent 打招呼。最后,超级 parent 确认他收到了每个 children.
的问候
我在添加管道之前测试了叉子,它们工作正常,产生了正确数量的 children。所以我几乎可以肯定问题出在我代码底部的两个 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);
}
}
}
如果有人能看一下我的代码并告诉我如何正确实现parent和children之间的通信,我将不胜感激。
1) 问题:未打印 printf:
stdout
在 Unix 下通常是行缓冲的。尝试打印到 stderr
(无缓冲),调用 fflush(stdout)
,或显式打印 "\n"
.
2) 问题:写入 & strcmp
请注意,您 write(fd, "Hi child\n", 9)
没有尾随 '[=15=]'
,但 strcmp 比较零终止字符串。因此,您的子进程永远不会响应。
通过管道的双向 IPC 有很多缺陷。参见 https://unix.stackexchange.com/questions/11946/how-big-is-the-pipe-buffer
您将 NUM_CHILDREN 设置为命令行参数的数量。如果您未能提供任何参数,则它为零,不进入循环,pid 未初始化并且未定义将采用底部的两条路径中的哪一条。两者都会挂起。
在不从 stdin 读取并且发生挂起的情况下使用 printf 时,您可能需要使用 fflush
来获取输出。
接下来,您的 parent 正在等待没有句点的消息,而您的 child 正在发送句点。
最后,parent 和 child 都在循环,直到另一个关闭,所以来自第一个 child 的通信不会结束,之后的 children 永远不会被处理.
我目前无法理解 non-duplex two-way children 和他们的 parent 之间的未命名管道通信。我正在尝试与超级 parent.
通信最多十个 children目前我正在尝试让超级 parent 向每个 children 打招呼,然后 children 向 parent 打招呼。最后,超级 parent 确认他收到了每个 children.
的问候我在添加管道之前测试了叉子,它们工作正常,产生了正确数量的 children。所以我几乎可以肯定问题出在我代码底部的两个 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);
}
}
}
如果有人能看一下我的代码并告诉我如何正确实现parent和children之间的通信,我将不胜感激。
1) 问题:未打印 printf:
stdout
在 Unix 下通常是行缓冲的。尝试打印到 stderr
(无缓冲),调用 fflush(stdout)
,或显式打印 "\n"
.
2) 问题:写入 & strcmp
请注意,您 write(fd, "Hi child\n", 9)
没有尾随 '[=15=]'
,但 strcmp 比较零终止字符串。因此,您的子进程永远不会响应。
通过管道的双向 IPC 有很多缺陷。参见 https://unix.stackexchange.com/questions/11946/how-big-is-the-pipe-buffer
您将 NUM_CHILDREN 设置为命令行参数的数量。如果您未能提供任何参数,则它为零,不进入循环,pid 未初始化并且未定义将采用底部的两条路径中的哪一条。两者都会挂起。
在不从 stdin 读取并且发生挂起的情况下使用 printf 时,您可能需要使用 fflush
来获取输出。
接下来,您的 parent 正在等待没有句点的消息,而您的 child 正在发送句点。
最后,parent 和 child 都在循环,直到另一个关闭,所以来自第一个 child 的通信不会结束,之后的 children 永远不会被处理.