如何使用pipe / excel最佳地构建4个进程之间的进程间通信?

时间:2012-02-25 03:21:50

标签: c exec fork pipe

我正在尝试使用管道/ 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");
 }  

2 个答案:

答案 0 :(得分:1)

你的问题有两个错误:

  •   

    我想将stdin从整个父进程/程序重定向到子进程

  •   
  父级的标准输入由子级继承,不能重定向。

  •   

    我认为最好得到另外两个子的pids   除了“s”/ scan进程之外我还需要创建的进程   并使用不同的pids作为参数调用相应的二进制文件

  •   
  没有必要将自己的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;
}

答案 1 :(得分:0)

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

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

  1. echo process关闭无用的管道。
  2. 父级读取值(如果失败,则将其设置为0)。
  3. parent将增加的值写入管道。
  4. 孩子execl到同一个程序。
  5. 那应该没问题。