我正在尝试创建一个进程的二进制树,其中每个父进程都通过管道连接到它的两个子进程。
问题:父进程A创建两个进程(B和C)和两个管道,每个进程一个。它们的文件描述符存储在fd中。在第二次迭代中,B产生了它的两个孩子。B用新管道的文件描述符覆盖存储在fd中的文件描述符。在生成n个级别后,剩下的管道只有到其父级的叶节点(向上一个级别)。
我已经测试了这个理论,唯一能交流的东西是在树的底部,树叶到更高的层次之间。我必须这样做,这样叶节点就可以一直向上通信到主进程。
我是管道新手,所以我可以不去解释。
我的理解正确吗?我应该怎么做才能解决这个问题?
样本代码:
#define READ 0
#define WRITE 1
int fd[2][2];
void
spawnChildren(int levels)
{
if(levels == 0)
return;
pipe(fd[0]);
//spawns 2 children at a single parent
int pid = fork();
//parent
if(pid > 0)
{
close(fd[0][WRITE]);
pipe(fd[1]);
int pid2 = fork();
//child B
if(pid2 == 0)
{
close(fd[1][READ]);
spawnChildren(levels-1);
return;
}
//parent
else
close(fd[1][WRITE]);
}
//child A
else
{
close(fd[0][READ]);
spawnChildren(levels-1);
return;
}
}
如果我理解正确,根进程已经打开了两个fd来与其两个子进程通信。然后他们只打开其他独立的管道。
当侄子四个时,根进程如何与他们通信?
您需要保持所有fd的打开状态;每个进程都必须从其子进程获取输入,并将其传递给其父进程;你需要某种协议来解决它们。数据下降也是如此。
例如,根父级希望与其左子级的右子级的左子级进行通信:
- 它将RL.HELO WORLD发送给它的左子
- 左边的孩子看到R并向右边的孩子发送#L.HELLO WORLD
- 右边的孩子接收#L.HELLO WORLD并将##.HELO WORLD发送给左边的孩子
-
左边的孩子收到##.HELO WORLD并知道消息是给它的
-
左边的孩子回答发送##。我听到你对它的父母
- 父母看到左边的孩子在说话,把最后一个#转换成L,然后向上发送
- 父母看到自己的孩子在说#L.我听到你了,就发送RL。我听到你
- 根接收RL。我从它的左边的孩子那里听到你的声音,知道它是谁发起的
当然,在这一点上,每个进程还必须有一个用于传入和传出消息的队列。
即使只在根和叶之间进行通信,也需要队列和消息传递;它只允许不使用"R#L"协议,但鉴于其简单性,这是一个非常小的节省。
您需要的是一个线程或进程侦听(读取)每个管道,然后将其写入相应的管道。本质上,每个"节点"都需要两个线程或进程来执行此操作,每个子级一个。
这不是很好的扩展性,根据你想要做的事情,如果你不能更好地设计它,你可能需要重新评估。一个建议是让你的叶节点写入临时文件而不是管道,然后让你的顶层智能地读取这些文件,而不是试图通过fork管理所有这些管道。这样做可以大量减少"节点"的数量。只是个主意。