使用管道的两种方式通信
Two way communicating using pipe
我有一个C语言练习管道和进程的小程序,有一个parent进程,有两个child进程(child_a,child_b ).有两个指针数组(每个指针指向一个结构(Rabbit)),parent 将其中一个发送到 child_a,另一个发送到 child_b(使用管道)。我使用 4 个管道进行通信:pipefd_a1 和 pipefd_b1 用于 parent->child,另外 2 个用于 child->parent 方法。 child 进程修改元素然后将它们发送回 parent。然后 parent 向控制台写入一些内容。所以它一直工作到最后一个 child 进程从管道读取最后一个数据然后程序挂起。它向控制台写入一个数字(2034、10987 等),然后挂起。我怎样才能解决这个问题,为什么 while 循环中没有 return?我在读取它之前不是关闭了所有管道吗?
typedef struct Rabbit {
char* name;
char* district;
unsigned part_count;
unsigned eggs_count;
} Rabbit;
int pipefd_a1[2], pipefd_a2[2];
int pipefd_b1[2], pipefd_b2[2];
pid_t child_a, child_b;
// Pipe error checking
...
Rabbit** rabbits_a = (Rabbit**)malloc(sizeof(Rabbit*) * size);
Rabbit** rabbits_b = (Rabbit**)malloc(sizeof(Rabbit*) * size);
// Setting the array values (with malloc calls ofc)
...
// count_a is the size of rabbits_a, count_b is the size of rabbits_b
for (unsigned i = 0; i < count_a; ++i) {
Rabbit rabbit = {rabbits_a[i]->name, rabbits_a[i]->district, rabbits_a[i]->part_count, rabbits_a[i]->eggs_count};
write(pipefd_a1[1], &rabbit, sizeof(Rabbit));
}
for (unsigned i = 0; i < count_b; ++i) {
Rabbit rabbit = {rabbits_b[i]->name, rabbits_b[i]->district, rabbits_b[i]->part_count, rabbits_b[i]->eggs_count};
write(pipefd_b1[1], &rabbit, sizeof(Rabbit));
}
child_a = fork();
if (child_a == 0) { // Child A
close(pipefd_a2[0]);
close(pipefd_a1[1]);
Rabbit* rabbits = (Rabbit*)malloc(sizeof(Rabbit) * size);
Rabbit rabbit;
unsigned count_rabbits = 0;
while (read(pipefd_a1[0], &rabbit, sizeof(Rabbit))) {
// Do something with rabbit
rabbits[count_rabbits++] = rabbit;
}
close(pipefd_a1[0]);
for (unsigned i = 0; i < count_rabbits; ++i) {
write(pipefd_a2[1], &rabbits[i], sizeof(Rabbit));
}
close(pipefd_a2[1]);
} else {
child_b = fork();
if (child_b == 0) { // Child B
close(pipefd_b2[0]);
close(pipefd_b1[1]);
Rabbit* rabbits = (Rabbit*)malloc(sizeof(Rabbit) * size);
Rabbit rabbit;
unsigned count_rabbits = 0;
while (read(pipefd_b1[0], &rabbit, sizeof(Rabbit))) {
// Do something with rabbit
rabbits[count_rabbits++] = rabbit;
}
// The execution does not reach this point
close(pipefd_b1[0]);
for (unsigned i = 0; i < count_rabbits; ++i) {
write(pipefd_b2[1], &rabbits[i], sizeof(Rabbit));
}
close(pipefd_b2[1]);
} else { // Parent
pid_t pids[] = {child_a, child_b};
pid_t returned_pid;
for (unsigned i = 0; i < 2; ++i) {
struct stat dummy;
char buf[70];
sprintf(buf, "ps -e | awk '{ print }' | grep %d", pids[i]);
int result = system(buf);
if (result != 0) {
continue;
}
do {
returned_pid = wait(NULL);
} while (returned_pid != pids[i]);
}
}
}
这是我对您的代码所做的编辑。我重新组织了操作顺序,以便 child 进程无法 'cheat' 通过让 parent 应该发送给 children 的信息已经可用。这段代码编译;我没有 运行 因为我不擅长养兔子而且你的代码在应该创建兔子信息的地方不完整。
注意过多的 close()
电话。每个 child 都需要关闭另一个 child 的所有四个管道描述符,以及它不会使用的两个。 parent 进程必须关闭八个管道描述符。我已经重写了等待处理——我认为你的做法不合适。除此之外,如果 'wrong' child 先死,你就会有问题。而且 运行ning ps | awk | grep
不好 — 单独使用 awk
或单独使用 grep
但不能同时使用。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/wait.h>
#include <unistd.h>
typedef struct Rabbit
{
char *name;
char *district;
unsigned part_count;
unsigned eggs_count;
} Rabbit;
int main(void)
{
int pipefd_a1[2], pipefd_a2[2];
int pipefd_b1[2], pipefd_b2[2];
pid_t child_a, child_b;
if (pipe(pipefd_a1) != 0 ||
pipe(pipefd_a2) != 0 ||
pipe(pipefd_b1) != 0 ||
pipe(pipefd_b2) != 0)
{
perror("pipe");
exit(EXIT_FAILURE);
}
size_t size = 20;
Rabbit **rabbits_a = (Rabbit **)malloc(sizeof(Rabbit *) * size);
Rabbit **rabbits_b = (Rabbit **)malloc(sizeof(Rabbit *) * size);
unsigned count_a = 10;
unsigned count_b = 8;
if ((child_a = fork()) < 0)
{
perror("fork");
exit(EXIT_FAILURE);
}
else if (child_a == 0) // Child A
{
/* Not using b1 or b2 pipes at all */
close(pipefd_b1[0]);
close(pipefd_b1[1]);
close(pipefd_b2[0]);
close(pipefd_b2[1]);
close(pipefd_a1[1]);
close(pipefd_a2[0]);
Rabbit *rabbits = (Rabbit *)malloc(sizeof(Rabbit) * size);
Rabbit rabbit;
unsigned count_rabbits = 0;
while (read(pipefd_a1[0], &rabbit, sizeof(Rabbit)))
{
// Do something with rabbit
rabbits[count_rabbits++] = rabbit;
}
close(pipefd_a1[0]);
for (unsigned i = 0; i < count_rabbits; ++i)
{
write(pipefd_a2[1], &rabbits[i], sizeof(Rabbit));
}
close(pipefd_a2[1]);
}
else if ((child_b = fork()) == -1)
{
perror("fork");
exit(EXIT_FAILURE);
}
else if (child_b == 0)
{
/* Not using a1 or a2 pipes at all */
close(pipefd_a1[0]);
close(pipefd_a1[1]);
close(pipefd_a2[0]);
close(pipefd_a2[1]);
close(pipefd_b1[1]);
close(pipefd_b2[0]);
Rabbit *rabbits = (Rabbit *)malloc(sizeof(Rabbit) * size);
Rabbit rabbit;
unsigned count_rabbits = 0;
while (read(pipefd_b1[0], &rabbit, sizeof(Rabbit)))
{
rabbits[count_rabbits++] = rabbit;
}
close(pipefd_b1[0]);
for (unsigned i = 0; i < count_rabbits; ++i)
{
write(pipefd_b2[1], &rabbits[i], sizeof(Rabbit));
}
close(pipefd_b2[1]);
}
else
{
for (unsigned i = 0; i < count_a; ++i)
{
Rabbit rabbit = {rabbits_a[i]->name, rabbits_a[i]->district, rabbits_a[i]->part_count, rabbits_a[i]->eggs_count};
write(pipefd_a1[1], &rabbit, sizeof(Rabbit));
}
for (unsigned i = 0; i < count_b; ++i)
{
Rabbit rabbit = {rabbits_b[i]->name, rabbits_b[i]->district, rabbits_b[i]->part_count, rabbits_b[i]->eggs_count};
write(pipefd_b1[1], &rabbit, sizeof(Rabbit));
}
/* Close pipes so child processes get EOF */
close(pipefd_a1[0]);
close(pipefd_a1[1]);
close(pipefd_a2[0]);
close(pipefd_a2[1]);
close(pipefd_b1[0]);
close(pipefd_b1[1]);
close(pipefd_b2[0]);
close(pipefd_b2[1]);
int corpse;
int status;
while ((corpse = wait(&status)) > 0)
printf("Child %d exited with status 0x%.4X\n", corpse, status);
}
return 0;
}
我有一个C语言练习管道和进程的小程序,有一个parent进程,有两个child进程(child_a,child_b ).有两个指针数组(每个指针指向一个结构(Rabbit)),parent 将其中一个发送到 child_a,另一个发送到 child_b(使用管道)。我使用 4 个管道进行通信:pipefd_a1 和 pipefd_b1 用于 parent->child,另外 2 个用于 child->parent 方法。 child 进程修改元素然后将它们发送回 parent。然后 parent 向控制台写入一些内容。所以它一直工作到最后一个 child 进程从管道读取最后一个数据然后程序挂起。它向控制台写入一个数字(2034、10987 等),然后挂起。我怎样才能解决这个问题,为什么 while 循环中没有 return?我在读取它之前不是关闭了所有管道吗?
typedef struct Rabbit {
char* name;
char* district;
unsigned part_count;
unsigned eggs_count;
} Rabbit;
int pipefd_a1[2], pipefd_a2[2];
int pipefd_b1[2], pipefd_b2[2];
pid_t child_a, child_b;
// Pipe error checking
...
Rabbit** rabbits_a = (Rabbit**)malloc(sizeof(Rabbit*) * size);
Rabbit** rabbits_b = (Rabbit**)malloc(sizeof(Rabbit*) * size);
// Setting the array values (with malloc calls ofc)
...
// count_a is the size of rabbits_a, count_b is the size of rabbits_b
for (unsigned i = 0; i < count_a; ++i) {
Rabbit rabbit = {rabbits_a[i]->name, rabbits_a[i]->district, rabbits_a[i]->part_count, rabbits_a[i]->eggs_count};
write(pipefd_a1[1], &rabbit, sizeof(Rabbit));
}
for (unsigned i = 0; i < count_b; ++i) {
Rabbit rabbit = {rabbits_b[i]->name, rabbits_b[i]->district, rabbits_b[i]->part_count, rabbits_b[i]->eggs_count};
write(pipefd_b1[1], &rabbit, sizeof(Rabbit));
}
child_a = fork();
if (child_a == 0) { // Child A
close(pipefd_a2[0]);
close(pipefd_a1[1]);
Rabbit* rabbits = (Rabbit*)malloc(sizeof(Rabbit) * size);
Rabbit rabbit;
unsigned count_rabbits = 0;
while (read(pipefd_a1[0], &rabbit, sizeof(Rabbit))) {
// Do something with rabbit
rabbits[count_rabbits++] = rabbit;
}
close(pipefd_a1[0]);
for (unsigned i = 0; i < count_rabbits; ++i) {
write(pipefd_a2[1], &rabbits[i], sizeof(Rabbit));
}
close(pipefd_a2[1]);
} else {
child_b = fork();
if (child_b == 0) { // Child B
close(pipefd_b2[0]);
close(pipefd_b1[1]);
Rabbit* rabbits = (Rabbit*)malloc(sizeof(Rabbit) * size);
Rabbit rabbit;
unsigned count_rabbits = 0;
while (read(pipefd_b1[0], &rabbit, sizeof(Rabbit))) {
// Do something with rabbit
rabbits[count_rabbits++] = rabbit;
}
// The execution does not reach this point
close(pipefd_b1[0]);
for (unsigned i = 0; i < count_rabbits; ++i) {
write(pipefd_b2[1], &rabbits[i], sizeof(Rabbit));
}
close(pipefd_b2[1]);
} else { // Parent
pid_t pids[] = {child_a, child_b};
pid_t returned_pid;
for (unsigned i = 0; i < 2; ++i) {
struct stat dummy;
char buf[70];
sprintf(buf, "ps -e | awk '{ print }' | grep %d", pids[i]);
int result = system(buf);
if (result != 0) {
continue;
}
do {
returned_pid = wait(NULL);
} while (returned_pid != pids[i]);
}
}
}
这是我对您的代码所做的编辑。我重新组织了操作顺序,以便 child 进程无法 'cheat' 通过让 parent 应该发送给 children 的信息已经可用。这段代码编译;我没有 运行 因为我不擅长养兔子而且你的代码在应该创建兔子信息的地方不完整。
注意过多的 close()
电话。每个 child 都需要关闭另一个 child 的所有四个管道描述符,以及它不会使用的两个。 parent 进程必须关闭八个管道描述符。我已经重写了等待处理——我认为你的做法不合适。除此之外,如果 'wrong' child 先死,你就会有问题。而且 运行ning ps | awk | grep
不好 — 单独使用 awk
或单独使用 grep
但不能同时使用。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/wait.h>
#include <unistd.h>
typedef struct Rabbit
{
char *name;
char *district;
unsigned part_count;
unsigned eggs_count;
} Rabbit;
int main(void)
{
int pipefd_a1[2], pipefd_a2[2];
int pipefd_b1[2], pipefd_b2[2];
pid_t child_a, child_b;
if (pipe(pipefd_a1) != 0 ||
pipe(pipefd_a2) != 0 ||
pipe(pipefd_b1) != 0 ||
pipe(pipefd_b2) != 0)
{
perror("pipe");
exit(EXIT_FAILURE);
}
size_t size = 20;
Rabbit **rabbits_a = (Rabbit **)malloc(sizeof(Rabbit *) * size);
Rabbit **rabbits_b = (Rabbit **)malloc(sizeof(Rabbit *) * size);
unsigned count_a = 10;
unsigned count_b = 8;
if ((child_a = fork()) < 0)
{
perror("fork");
exit(EXIT_FAILURE);
}
else if (child_a == 0) // Child A
{
/* Not using b1 or b2 pipes at all */
close(pipefd_b1[0]);
close(pipefd_b1[1]);
close(pipefd_b2[0]);
close(pipefd_b2[1]);
close(pipefd_a1[1]);
close(pipefd_a2[0]);
Rabbit *rabbits = (Rabbit *)malloc(sizeof(Rabbit) * size);
Rabbit rabbit;
unsigned count_rabbits = 0;
while (read(pipefd_a1[0], &rabbit, sizeof(Rabbit)))
{
// Do something with rabbit
rabbits[count_rabbits++] = rabbit;
}
close(pipefd_a1[0]);
for (unsigned i = 0; i < count_rabbits; ++i)
{
write(pipefd_a2[1], &rabbits[i], sizeof(Rabbit));
}
close(pipefd_a2[1]);
}
else if ((child_b = fork()) == -1)
{
perror("fork");
exit(EXIT_FAILURE);
}
else if (child_b == 0)
{
/* Not using a1 or a2 pipes at all */
close(pipefd_a1[0]);
close(pipefd_a1[1]);
close(pipefd_a2[0]);
close(pipefd_a2[1]);
close(pipefd_b1[1]);
close(pipefd_b2[0]);
Rabbit *rabbits = (Rabbit *)malloc(sizeof(Rabbit) * size);
Rabbit rabbit;
unsigned count_rabbits = 0;
while (read(pipefd_b1[0], &rabbit, sizeof(Rabbit)))
{
rabbits[count_rabbits++] = rabbit;
}
close(pipefd_b1[0]);
for (unsigned i = 0; i < count_rabbits; ++i)
{
write(pipefd_b2[1], &rabbits[i], sizeof(Rabbit));
}
close(pipefd_b2[1]);
}
else
{
for (unsigned i = 0; i < count_a; ++i)
{
Rabbit rabbit = {rabbits_a[i]->name, rabbits_a[i]->district, rabbits_a[i]->part_count, rabbits_a[i]->eggs_count};
write(pipefd_a1[1], &rabbit, sizeof(Rabbit));
}
for (unsigned i = 0; i < count_b; ++i)
{
Rabbit rabbit = {rabbits_b[i]->name, rabbits_b[i]->district, rabbits_b[i]->part_count, rabbits_b[i]->eggs_count};
write(pipefd_b1[1], &rabbit, sizeof(Rabbit));
}
/* Close pipes so child processes get EOF */
close(pipefd_a1[0]);
close(pipefd_a1[1]);
close(pipefd_a2[0]);
close(pipefd_a2[1]);
close(pipefd_b1[0]);
close(pipefd_b1[1]);
close(pipefd_b2[0]);
close(pipefd_b2[1]);
int corpse;
int status;
while ((corpse = wait(&status)) > 0)
printf("Child %d exited with status 0x%.4X\n", corpse, status);
}
return 0;
}