许多 child 进程与单个 parent 通信
Many child processes communicating to single parent
我需要尝试生成一个 parent 并与多个 child 进程进行有意义的通信。这意味着发送数据并让他们将数据发送回单个 parent。首先,我一直在尝试让我的 children 输出一些东西并让我的 parent 捕捉它,最终目标是允许所有 children 之间的双向通信parent。为此,我为每个 children 实例化了两个管道,并将所有管道存储到一个名为 pipes
的多维数组中。多维管道数组存储使得每个索引 i
用于 ith + 1
child 并且 [i][0]
索引具有专门用于 parent
的管道到 child
,[i][1]
索引有一个专门供 child
与 parent
通信的管道。 children
进程都是非常简单的派生,只执行这段代码:
foo.c
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char ** argv) {
printf("Hi there!");
close(STDOUT_FILENO); //Close our write end
close(STDIN_FILENO); //Close our read end
//Else do nothing
return 0;
}
我的主要代码位于此,它首先创建所有必要的管道(每个 children 有 2 个)。然后我 dup2
STDIN
和 STDOUT
所以 printf
打印到我想要的管道。
fork_complex.c
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <strings.h>
#include <math.h>
#define MAXSIZE 4096
#define CHILDREN 5
int main(int argc, char ** argv) {
//Needs command line arguments
int ** pipes[CHILDREN]; //The multi-dimensional array that contains CHILDREN pipes
//Allocate the space
for (int i = 0; i < CHILDREN; i++) {
//Each children will need two pipes, one for comunicating and one for writing
pipes[i] = malloc(sizeof(int*) * 2);
pipes[i][0] = malloc(sizeof(int) * 2); //This pipe is specifically parent to child
pipes[i][1] = malloc(sizeof(int) * 2); //This pipe is for specifically for the child to parent
//Create the pipes
if (pipe(pipes[i][0]) == -1 || pipe(pipes[i][1]) == -1) {
//There was a failure in generating one of the pipes
perror("Error on generating the pipe");
}
}
//Spawn the child processses
for (int i = 0; i < CHILDREN; i++) {
int status = fork(); //Fork a child
switch (status) {
case -1:
perror("Failed to fork the process");
exit(1);
break;
case 0:
//Child process, exec the floor
dup2(pipes[i][0][0], fileno(stdin));
dup2(pipes[i][1][1], fileno(stdout));
execl("./foo", "");
break;
}
//Parent continues the loop to spawn more children
}
char readed[MAXSIZE] = ""; //Reading buffer
//Now read back from the pipes
for (int i = 0; i < CHILDREN; i++) {
while (read(pipes[i][1][0], readed, MAXSIZE) > 0) {
printf("From pipe %d, we have read %s\n", i, readed);
}
}
return 1;
}
但是,我的代码似乎一直卡在底部的 while
块中以从管道中读取,因为当我删除它时,代码会完全执行。我有一些猜测,可能我们有僵尸 children(因为它们在 parent 可能进入 for 循环之前终止)。我不确定当 child 死亡时管道会发生什么(除此之外与其相关的文件描述符已关闭)我们仍然可以从中读取(我对此也很好奇)。但是,根据我过去的经验,您似乎仍然可以。我已经被这个问题困了几个小时,任何见解都将不胜感激(或者我可能做错了什么)!
当您 read
4096
字节时,某些系统(如 linux)将尝试满足完整请求并阻塞直到另一端 1) 写入所有 4096
字节或 2) 关闭写端。
write end的所有duplicates都需要关闭,不只有一个。
dup
ing 创建对文件描述符的新引用。当您 fork
时,就好像您 dup
编辑了您当时打开的所有文件描述符。
要完成 read
,您要么需要满足完整的 4096 字节请求,要么生成 EOF,要使后者发生,需要关闭写入端的所有克隆。
因为您的每个 children execs,您可以做的是设置每个管道 O_CLOEXEC
(使用 fcntl
),并且 close
每个写入结束parent 在你 fork 掉 child 之后,将写入到写入端。
(除此之外,请确保包含您需要的所有 headers 并确保您处理所有错误)。
我需要尝试生成一个 parent 并与多个 child 进程进行有意义的通信。这意味着发送数据并让他们将数据发送回单个 parent。首先,我一直在尝试让我的 children 输出一些东西并让我的 parent 捕捉它,最终目标是允许所有 children 之间的双向通信parent。为此,我为每个 children 实例化了两个管道,并将所有管道存储到一个名为 pipes
的多维数组中。多维管道数组存储使得每个索引 i
用于 ith + 1
child 并且 [i][0]
索引具有专门用于 parent
的管道到 child
,[i][1]
索引有一个专门供 child
与 parent
通信的管道。 children
进程都是非常简单的派生,只执行这段代码:
foo.c
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char ** argv) {
printf("Hi there!");
close(STDOUT_FILENO); //Close our write end
close(STDIN_FILENO); //Close our read end
//Else do nothing
return 0;
}
我的主要代码位于此,它首先创建所有必要的管道(每个 children 有 2 个)。然后我 dup2
STDIN
和 STDOUT
所以 printf
打印到我想要的管道。
fork_complex.c
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <strings.h>
#include <math.h>
#define MAXSIZE 4096
#define CHILDREN 5
int main(int argc, char ** argv) {
//Needs command line arguments
int ** pipes[CHILDREN]; //The multi-dimensional array that contains CHILDREN pipes
//Allocate the space
for (int i = 0; i < CHILDREN; i++) {
//Each children will need two pipes, one for comunicating and one for writing
pipes[i] = malloc(sizeof(int*) * 2);
pipes[i][0] = malloc(sizeof(int) * 2); //This pipe is specifically parent to child
pipes[i][1] = malloc(sizeof(int) * 2); //This pipe is for specifically for the child to parent
//Create the pipes
if (pipe(pipes[i][0]) == -1 || pipe(pipes[i][1]) == -1) {
//There was a failure in generating one of the pipes
perror("Error on generating the pipe");
}
}
//Spawn the child processses
for (int i = 0; i < CHILDREN; i++) {
int status = fork(); //Fork a child
switch (status) {
case -1:
perror("Failed to fork the process");
exit(1);
break;
case 0:
//Child process, exec the floor
dup2(pipes[i][0][0], fileno(stdin));
dup2(pipes[i][1][1], fileno(stdout));
execl("./foo", "");
break;
}
//Parent continues the loop to spawn more children
}
char readed[MAXSIZE] = ""; //Reading buffer
//Now read back from the pipes
for (int i = 0; i < CHILDREN; i++) {
while (read(pipes[i][1][0], readed, MAXSIZE) > 0) {
printf("From pipe %d, we have read %s\n", i, readed);
}
}
return 1;
}
但是,我的代码似乎一直卡在底部的 while
块中以从管道中读取,因为当我删除它时,代码会完全执行。我有一些猜测,可能我们有僵尸 children(因为它们在 parent 可能进入 for 循环之前终止)。我不确定当 child 死亡时管道会发生什么(除此之外与其相关的文件描述符已关闭)我们仍然可以从中读取(我对此也很好奇)。但是,根据我过去的经验,您似乎仍然可以。我已经被这个问题困了几个小时,任何见解都将不胜感激(或者我可能做错了什么)!
当您 read
4096
字节时,某些系统(如 linux)将尝试满足完整请求并阻塞直到另一端 1) 写入所有 4096
字节或 2) 关闭写端。
write end的所有duplicates都需要关闭,不只有一个。
dup
ing 创建对文件描述符的新引用。当您 fork
时,就好像您 dup
编辑了您当时打开的所有文件描述符。
要完成 read
,您要么需要满足完整的 4096 字节请求,要么生成 EOF,要使后者发生,需要关闭写入端的所有克隆。
因为您的每个 children execs,您可以做的是设置每个管道 O_CLOEXEC
(使用 fcntl
),并且 close
每个写入结束parent 在你 fork 掉 child 之后,将写入到写入端。
(除此之外,请确保包含您需要的所有 headers 并确保您处理所有错误)。