Parent - 两个 Child 相互交流的正确方式
Parent - Two Child correct way to communicate with each other
我有一个小程序,其中有一个parent进程和两个child进程 .首先,parent 进程通过管道将数据发送到它的 children (childA, childB)。为了更清楚,我有一个指针数组,其中包含指向结构(Rabbit)的元素。 parent 进程过滤此数组并将过滤后的数据发送到 childA 和 childB 相同,只是此数据会有所不同。然后 childA 和 childB 对其数据进行处理并将其发送回 parent 进程。我必须用 pipes 来实现它。这个代码片段有什么问题,我该如何解决这个问题?
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 }' | 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 '{ 打印 $1 }' | grep %d`
这是一串三个 shell 命令:
ps -e
- 这将打印有关所有当前 运行ning 进程的信息。这包括进程 ID
awk '{ print }'
- 这个 运行 是一个 awk 脚本,它只打印给定字符串中的第一个字段,其中字段由空格分隔
grep %d
- 这将在给定文件(在本例中为标准输入)中搜索提供的 PID(因为这是格式字符串,%d
被替换为进程 ID)
然后,system
命令运行整个字符串。 return 值为 0 表示命令字符串已成功执行,这意味着在当前 运行ning 进程列表中找到了进程 ID。
无论如何,我希望你能从这篇文章中得到一些有价值的信息post。
我有一个小程序,其中有一个parent进程和两个child进程 .首先,parent 进程通过管道将数据发送到它的 children (childA, childB)。为了更清楚,我有一个指针数组,其中包含指向结构(Rabbit)的元素。 parent 进程过滤此数组并将过滤后的数据发送到 childA 和 childB 相同,只是此数据会有所不同。然后 childA 和 childB 对其数据进行处理并将其发送回 parent 进程。我必须用 pipes 来实现它。这个代码片段有什么问题,我该如何解决这个问题?
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 }' | 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 '{ 打印 $1 }' | grep %d`
这是一串三个 shell 命令:
ps -e
- 这将打印有关所有当前 运行ning 进程的信息。这包括进程 IDawk '{ print }'
- 这个 运行 是一个 awk 脚本,它只打印给定字符串中的第一个字段,其中字段由空格分隔grep %d
- 这将在给定文件(在本例中为标准输入)中搜索提供的 PID(因为这是格式字符串,%d
被替换为进程 ID)
然后,system
命令运行整个字符串。 return 值为 0 表示命令字符串已成功执行,这意味着在当前 运行ning 进程列表中找到了进程 ID。
无论如何,我希望你能从这篇文章中得到一些有价值的信息post。