Pipe()和fork()

时间:2017-12-12 16:01:23

标签: c pipe fork file-descriptor

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

  1. 进程p1从管道c1读取并写入管道c2
  2. 进程p2从管道c2读取并写入管道c1
  3. 直到管道中的读数小于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);
    }
    

3 个答案:

答案 0 :(得分:3)

你的程序有点奇怪。主要问题似乎是第二个fork在主程序和第一个子程序中执行。事实上,你正在运行四个过程:主要的,两个主要的儿子和第一个儿子的儿子。这可能不是你想要的。您可能希望在第一个switch之后立即放置第一个fork,并仅在主程序中执行第二个fork

当然,对于意外情况,您不会检查readwrite的结果值。

答案 1 :(得分:1)

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

而不是:

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

你需要这样写:

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

答案 2 :(得分:0)

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

由于您的孩子在他们完成后处理关闭管道,您很有可能进入竞争条件,其中一个进程在另一个进程读取最新值c之前关闭管道。将您的来电置于fork会更加复杂,因为目前最终会有3个子流程而不是2个。

您应该在fork之后将第二次调用移至switch,因为您知道此时您只能在父进程中,并且还会将管道的关闭移动到父级。 / p>