管道()和叉子()

Pipe() and fork()

我的程序的目标是创建两个管道和两个相互通信的进程,以读取和写入管道。

  1. 进程 p1 从管道 c1 读取并写入管道 c2
  2. 进程 p2 从管道 c2 读取并写入管道 c1

直到从管道读取的数字小于BIG_INT_STOP,这两个进程继续增加管道中的数字。一旦这个条件为真,第一个进程读取它,关闭管道,退出并打印数字。 问题是:当进程 p2 在 p1 之前结束时它工作,当进程 p1 在 p2 之前结束时它进入循环。 你能解释一下为什么吗?

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/sysinfo.h>
#include <sys/wait.h>
#include <errno.h>
#include <time.h>
#include <string.h>
#define BIG_INT_STOP 40
#define TEST_ERROR    if (errno) {fprintf(stderr, \
                  "%s:%d: PID=%5d: Error %d (%s)\n", \
                  __FILE__,         \
                  __LINE__,         \
                  getpid(),         \
                  errno,            \
                  strerror(errno));}

int main(){
  int c1[2], c2[2], p1, p2, z;
  long a = 0, c;
  pipe(c1);
  pipe(c2);
  write(c1[1], &a, sizeof(a));
  write(c2[1], &a, sizeof(a));
  p1 = fork();
  p2 = fork();
  switch(p1){
    case -1:
      TEST_ERROR;
      exit(EXIT_FAILURE);
    case 0:
      read(c1[0], &c, sizeof(c));
      while(c != BIG_INT_STOP){
        ++c;
        write(c2[1], &c, sizeof(c));
        read(c1[0], &c, sizeof(c));
      }
      close(c1[0]);
      close(c1[1]);
      close(c2[0]);
      close(c2[1]);
      printf("p1: %ld\n", c);
      exit(0);
  }
  switch(p2){
    case -1:
      TEST_ERROR;
      exit(EXIT_FAILURE);
    case 0:
      read(c2[0], &c, sizeof(c));
      while(c != BIG_INT_STOP){
        ++c;
        write(c1[1], &c, sizeof(c));
        read(c2[0], &c, sizeof(c));
      }
      close(c1[0]);
      close(c1[1]);
      close(c2[0]);
      close(c2[1]);
      printf("p2: %ld\n", c);
      exit(0);
  }
  while(wait(&z) != -1);
}

你的程序有点奇怪。主要问题似乎是第二个 fork 在主程序和第一个子程序中执行。实际上你是运行四个进程:main,main的两个儿子和第一个儿子的儿子。这可能不是您想要的。您可能希望将第一个 switch 紧跟在第一个 fork 之后,并仅在主程序中执行第二个 fork

当然,您不会检查 readwrite 的结果值以发现意外情况。

问题是 p2 分叉了 2 次。一次在父进程,第二次在p1进程。

而不是:

  p1 = fork();
  p2 = fork();

你需要这样写:

p1 = fork();
if (p1 > 0) {
        p2 = fork();
}

您的代码没有对 readwrite 的调用进行正确的错误检查,这意味着如果从管道读取时出现问题,子进程将进入永无止境的循环因为 c 的值永远不会达到终止值。

由于您的子进程在完成后关闭管道,因此您很有可能进入竞争状态,其中一个进程在另一个进程读取 c 的最新值之前关闭管道.您调用 fork 的位置使情况更加复杂,因为目前您最终得到 3 个子进程,而不是 2 个。

您应该在 switch 之后将第二次调用移至 fork 因为您知道此时您只能在父进程中并将管道的关闭移动到父进程.