如何在4个进程与管道/execl之间最佳地构建进程间通信?

如何在4个进程与管道/execl之间最佳地构建进程间通信?,c,exec,fork,pipe,C,Exec,Fork,Pipe,我正在尝试设置一个程序,它使用进程间通信在四个进程之间使用pipes/execl进行通信。这是演示管道使用的家庭作业问题的一部分,但我有点难以理解它(即流程树如何生长)。这些进程将成为我的系统上二进制文件的实例,因此使用execl。为了简要概述我要完成的工作,我想将stdin从整个父进程/程序重定向到一个名为“s”的子进程(在我的系统中是一个名为scan的二进制文件),该子进程解释单词。在“s”/scan中,它处理来自其stdin的单词,然后根据单词的不同,将单词发送/写入一个进程(“e”)或另

我正在尝试设置一个程序,它使用进程间通信在四个进程之间使用pipes/execl进行通信。这是演示管道使用的家庭作业问题的一部分,但我有点难以理解它(即流程树如何生长)。这些进程将成为我的系统上二进制文件的实例,因此使用execl。为了简要概述我要完成的工作,我想将stdin从整个父进程/程序重定向到一个名为“s”的子进程(在我的系统中是一个名为scan的二进制文件),该子进程解释单词。在“s”/scan中,它处理来自其stdin的单词,然后根据单词的不同,将单词发送/写入一个进程(“e”)或另一个进程(“o”)。e/o进程实际上是同一个二进制文件,只有符号链接到它们——它基本上做同样的事情

我将如何着手构建我的呼叫/家长程序来构建它?我必须在这个主程序中创建所有进程,否则我将在scan/“s”进程中创建两个子进程。我在下面写了一些代码,将主程序的stdin重定向到“s”进程,但我不确定在哪里分叉将连接到它的两个子进程。我认为最好得到除“s”/scan进程之外我需要创建的其他两个子进程的PID,并使用不同的PID作为参数调用相应的二进制文件,但我不确定。任何帮助都将不胜感激

 int s_to_e[2]; int s_to_o[2];
 int e_to_s[2]; int o_to_e[2];
 pid_t e_pid; pid_t o_pid; pid_t s_pid;

 if (pipe(s_to_e)) {          
      exit(1);
 }

 if (pipe(s_to_o)) {          
      exit(1);
 }

 if ( (s_pid = fork()) == -1) {
      fprintf(stderr, "Fork error! \n");
      exit(1);
 }

 int status;

 //Child progress of scan
 if (s_pid == 0) {
      //Redirect stdin to s
      //This probably isn't the best way to go about doing this
      dup2(0, s_to_e[0]);
      close(s_to_e[1]);

      //We need to replace the child fork with a new process
      if(execl("./scan", "./scan", NULL ) == -1) {
           printf("execl Error!");
           exit(1);
      }

 } else {
      printf("I am parent\n");
      wait(&status);
      printf("Done\n");
 }  

您可以设置一个动态变量以传入当前进程的编号,并使用非阻塞IO读取一个将由父级写入管道的值

这意味着fork之后,流程应该执行以下操作:

  • 关闭无用的管道
  • 父级读取值(如果失败,将其设置为0)
  • 父级将增加的值写入管道
  • execl
    到同一程序

  • 那应该没问题。

    您可以设置一个动态变量以传入当前进程的编号,并使用非阻塞IO读取一个值,该值将由父进程写入管道

    这意味着fork之后,流程应该执行以下操作:

  • 关闭无用的管道
  • 父级读取值(如果失败,将其设置为0)
  • 父级将增加的值写入管道
  • execl
    到同一程序

  • 那应该没问题。

    你的问题中有两个错误:

    • 我想将stdin从整个父进程/程序重定向到子进程
    父级的标准输入由子级继承,不可重定向

    • 我想最好是得到另外两个潜艇的PID 除了“s”/“扫描”过程之外,我还需要创建的过程 并使用不同的PID作为参数调用相应的二进制文件
    不需要将自己的id传递给进程;它总是可以通过
    getpid()
    获得它

    以下程序应满足您的要求,错误检查除外

    #define _GNU_SOURCE
    #include <fcntl.h>
    #include <unistd.h>
    #include <stdlib.h>
    
    main()
    {
        int s_to_o[2];  pipe2(s_to_o, O_CLOEXEC);
        int s_to_e[2];  pipe2(s_to_e, O_CLOEXEC);
        if (fork() == 0)
         dup2(s_to_o[1], 1),
         dup2(s_to_e[1], 2), exit(execl("scan", "scan", NULL));
        close(s_to_o[1]);
        close(s_to_e[1]);
        if (fork() == 0)
         dup2(s_to_o[0], 0), exit(execl("o", "o", NULL));
        close(s_to_o[0]);
        if (fork() == 0)
         dup2(s_to_e[0], 0), exit(execl("e", "e", NULL));
        close(s_to_e[0]);
        wait(NULL);
        return 0;
    }
    
    定义GNU源
    #包括
    #包括
    #包括
    main()
    {
    int s_to_o[2];pipe2(s_to_o,o_CLOEXEC);
    int s_to_e[2];pipe2(s_to_e,O_CLOEXEC);
    如果(fork()==0)
    dup2(s_to_o[1],1),
    dup2(s_to_e[1],2),退出(execl(“扫描”,“扫描”,NULL));
    关闭(s_至_o[1]);
    关闭(s_至_e[1]);
    如果(fork()==0)
    dup2(s_to_o[0],0),exit(execl(“o”,“o”,NULL));
    关闭(s_至_o[0]);
    如果(fork()==0)
    dup2(s_to_e[0],0),exit(execl(“e”,“e”,NULL));
    关闭(s_至_e[0]);
    等待(空);
    返回0;
    }
    
    您的问题中有两个错误:

    • 我想将stdin从整个父进程/程序重定向到子进程
    父级的标准输入由子级继承,不可重定向

    • 我想最好是得到另外两个潜艇的PID 除了“s”/“扫描”过程之外,我还需要创建的过程 并使用不同的PID作为参数调用相应的二进制文件
    不需要将自己的id传递给进程;它总是可以通过
    getpid()
    获得它

    以下程序应满足您的要求,错误检查除外

    #define _GNU_SOURCE
    #include <fcntl.h>
    #include <unistd.h>
    #include <stdlib.h>
    
    main()
    {
        int s_to_o[2];  pipe2(s_to_o, O_CLOEXEC);
        int s_to_e[2];  pipe2(s_to_e, O_CLOEXEC);
        if (fork() == 0)
         dup2(s_to_o[1], 1),
         dup2(s_to_e[1], 2), exit(execl("scan", "scan", NULL));
        close(s_to_o[1]);
        close(s_to_e[1]);
        if (fork() == 0)
         dup2(s_to_o[0], 0), exit(execl("o", "o", NULL));
        close(s_to_o[0]);
        if (fork() == 0)
         dup2(s_to_e[0], 0), exit(execl("e", "e", NULL));
        close(s_to_e[0]);
        wait(NULL);
        return 0;
    }
    
    定义GNU源
    #包括
    #包括
    #包括
    main()
    {
    int s_to_o[2];pipe2(s_to_o,o_CLOEXEC);
    int s_to_e[2];pipe2(s_to_e,O_CLOEXEC);
    如果(fork()==0)
    dup2(s_to_o[1],1),
    dup2(s_to_e[1],2),退出(execl(“扫描”,“扫描”,NULL));
    关闭(s_至_o[1]);
    关闭(s_至_e[1]);
    如果(fork()==0)
    dup2(s_to_o[0],0),exit(execl(“o”,“o”,NULL));
    关闭(s_至_o[0]);
    如果(fork()==0)
    dup2(s_to_e[0],0),exit(execl(“e”,“e”,NULL));
    关闭(s_至_e[0]);
    等待(空);
    返回0;
    }