C语言 Parent - Two - Child正确的相互通信方式



我有一个小程序,其中有一个父进程两个子进程. 首先,父进程通过管道将数据发送给它的子进程(childda、childdb)。为了更清楚,我有一个指针数组,其中的元素指向一个结构体(Rabbit)。父进程过滤该数组并将过滤后的数据发送给childda,将过滤后的数据发送给childdb,只是这些数据有所不同。然后,childda和childdb对其数据进行处理,并将其发送回父进程。我必须用管道来实现它. 这个代码片段有什么问题,我该如何解决这个问题?

int pipefd_a[2];
int pipefd_b[2];
pid_t child_a, child_b;
if (pipe(pipefd_a) == -1) {
perror("Error during opening pipe A!");
exit(EXIT_FAILURE);
}
if (pipe(pipefd_b) == -1) {
perror("Error during opening pipe B!");
exit(EXIT_FAILURE);
}
child_a = fork();
if (child_a == 0) {    // Child A
close(pipefd_a[1]);
Rabbit rabbit;
while (read(pipefd_a[0], &rabbit, sizeof(Rabbit))) {
// Do something
}
close(pipefd_a[0]);
} else {
child_b = fork();

if (child_b == 0) {    // Child B
close(pipefd_b[1]);
Rabbit rabbit;
while (read(pipefd_b[0], &rabbit, sizeof(Rabbit))) {
// Do something
}
close(pipefd_b[0]);
} else {
Rabbit** rabbits_a = (Rabbit**)malloc(sizeof(Rabbit*) * size);
...
// Filter, count_a will be the size of the filtered array
close(pipefd_a[0]);
for (unsigned i = 0; i < count_a; ++i) {
Rabbit rabbit = {rabbits_a[i]->name, rabbits_a[i]->district, rabbits_a[i]->part_count};
write(pipefd_a[1], &rabbit, sizeof(Rabbit));
}
...
// The same for B
...
fflush(NULL);
wait(NULL);
}
}

乍一看,您似乎在正确的轨道上,但是您在子进程中缺少一些代码,这些代码用于将处理过的数据写回管道,以便父进程可以拾取它。此外,您的wait()调用应该是在调用fork()之后父进程中的第一个调用,因为您不能保证子进程会在父进程之前运行。此外,您可能希望设置某种循环结构,以便在两个子进程尝试从其管道中读取之前,您可以wait直到它们终止。

所以,你的程序结构可能是这样的:
// #include <sys/stat.h>
#include <unistd.h>
// ...
// ... assuming there's code you didn't show that writes the initial data to the pipes to get it into the children processes...
child_a = fork();
if (child_a == 0) {
// Read from pipe, do stuff, and write to pipefd_a[1] (so you can't close it)
} else {
child_b = fork();
if (child_b == 0) {

// read from pipe, do stuff, and write to pipefd_b[1]
} else {
// Wait for both child processes to end
pid_t pids[] = {child_a, child_b};
pid_t returned_pid;

int i;
for (i = 0; i < 2; i++) {
// the wait() call will return the pid of the process that
// caused wait() to terminate. Since you forked off two processes
// wait could either return child_a or child_b, and we
// want to make sure both processes are finished prior to
// trying to read stuff from their pipes, hence the outer
// for loop
// Update: I realized that if the process is already dead, 
// then the do-while loop just runs forever, so I'm throwing in a check 
// to make sure the process is alive before starting the loop
struct stat dummy;
char buf[70];
// Every running process on a UNIX system has a corresponding 
// ID number and a corresponding subdirectory within the /proc 
// directory, so if the directory doesn't exist, the process doesn't exist either
// sprintf(buf, "/proc/%d", pids[i]);
// ---------------------------------------
// Edited again because I'm dumb and forgot 
// /proc doesn't exist on macOS (which is what I'm on). 
// If you're there, then you can do something like this, which I'll explain below.
sprintf(buf, "ps -e | awk '{ print $1 }' | grep %d", pids[i]);
int result = system(buf);

// If on Linux you can  do...
/* 
if ( stat(buf, &dummy) < 0 ) {
// Process is dead, continue
continue;
} */

// If on a UNIX system (mac or Linux)...
if (result != 0) {
// Process is dead, continue
continue;
}

do {
returned_pid = wait(NULL);
} while (returned_pid != pids[i]);
}
// At this point, both child processes have terminated, so NOW
// we can read from the pipes
// Read from pipefd_a[0]

// Read from pipefd_b[0]
}
}

那么,这个字符串到底是什么:' ps -e | awk '{print $1}' | grep %d '这是一个由三个shell命令组成的字符串:

  1. ps -e-这将打印所有当前正在运行的进程的信息。这包括进程id
  2. awk '{ print $1 }'-这将运行awk脚本,只打印给定字符串中的第一个字段,其中字段由空格分隔
  3. grep %d-这将搜索给定的文件(在本例中为stdin)提供的PID(因为这是一个格式字符串,%d被替换为进程ID)

然后,system命令运行整个字符串。返回值为0表示命令字符串执行成功,表示在当前运行的进程列表中找到了进程ID。

无论如何,我希望你能从这篇文章中得到一些有价值的信息。

最新更新