【问题标题】:Pipes between child processes in CC中子进程之间的管道
【发布时间】:2011-07-25 18:13:28
【问题描述】:

我以前见过这个问题,但还是有点困惑:如何在同一个父进程的子进程之间创建通信?我现在要做的就是将消息从第一个子进程传递给第 n 个子进程。我的想法是在父进程中创建 n-1 个管道,然后将父进程的末端重定向到下一个子进程。我想不通的是,如果没有创建下一个子进程,我们将如何从父进程重定向结束?我觉得我处理这个问题的方式有问题。

编辑:我的目标是打印从第一个子进程传递到最后一个子进程的消息。这是一个简单的程序。

【问题讨论】:

  • 恕我直言,您应该描述您的最终目标。这将有助于人们提出解决方案。
  • 这是作业还是真正的问题?答案取决于此。对于实际问题,您应该考虑采用不同的 IPC 方法,如答案中所建议的那样。
  • 子进程是否与父进程不同?也就是说,子进程会在fork之后执行exec吗?并且,您是否需要将管道连接到标准文件描述符(0 表示输入,1 表示输出,2 表示错误输出)?
  • 这只是一个简单的管道练习;对他们没有太多经验。所以基本上我在程序中有一个字符串,我只想通过子进程传递。最后,最后一个子进程将打印字符串。

标签: c unix process pipe


【解决方案1】:

您无需先创建流程。解决方案如下:首先创建所有需要的管道,将它们保存在某个数组中。然后执行fork,相应地重定向输入和输出流(用于子进程),关闭未使用的管道端并执行exec。管道可以在没有相应进程的情况下存在,它们有缓冲区,所以你可以在没有人还在阅读的情况下写入管道,就可以了。

在执行exec 之前,您应该注意关闭未使用的 id。并小心写入输入端点(所有输入端点)可能关闭的管道:它可能导致SIGPIPE

【讨论】:

  • 如何将管道的 read() 和 write() 端从父进程重定向到子进程。
  • pipe 函数返回一对文件描述符,对吧? “返回”是指“写入指定数组”,如int fds[2]; pipe( fds );writeread 接受文件描述符作为它们的参数,所以你可以 read( fds[0], .... ) 和/或 write(fds[1], ...)
【解决方案2】:

设置管道并将 stadin/stdout 重定向到管道的代码是。

在父级(fork 之前)

   int p[2];
   pipe(p);

在子进程中(fork 之后)获取管道作为标准输入

   close(0);
   dup(p[0]);

在子进程中(fork 之后)将管道作为标准输出

  close(1);
  dup(p[1]);

您可以在创建管道后立即开始写入。然而,一旦管道缓冲区被填满,这个正在写入管道的子进程将暂停,直到另一个进程开始从管道读取。

还要查看 popen call,因为这实际上可能是您需要的更简单的版本。

【讨论】:

    【解决方案3】:

    除了使用未命名的管道之外,您可能还想研究一种用于进程间通信的替代机制,例如使用 FIFO、消息队列或使用数据报(即 UDP)的套接字,这将允许您将“消息”写入通信缓冲区,然后让另一个孩子阅读该消息,看看它是否适合他们,如果不是,让他们将其放回通信缓冲区中以供另一个孩子阅读。否则,如果消息是给他们的,他们就会接受。

    您的消息可以是 struct,其中包含发送者 ID、接收者 ID,然后是一些用于保存消息的缓冲区,无论是字符串类型等等。

    通信缓冲区可以由父级设置,并由子级继承。

    【讨论】:

      【解决方案4】:

      在简化的非exec 情况下,您应该执行类似的操作。

      #define nproc 17
      
      int pipes[nproc - 1][2];
      int pids[nproc];
      
      int i;
      for( i = 0; i < nproc - 1; i++ ) {
          pipe( pipes[i] );
      }
      
      int rank;
      for( rank = 0; rank < nproc; rank++ ) {
          pids[rank] = fork();
          if( !pids[rank] ) {
              if( rank == 0 ) {
                  write( pipe[rank][1], /* your message */ );
              }
      
              read( pipe[rank-1][0], /* read the message somewhere*/ );
      
              if( rank < nproc - 1 ) {
                  write( pipe[rank][1], /* write the message to the next child process*/ );
              } else {
                  // Here print the received message (it's already received above)
              }
          }
      }
      
      for( rank = 0; rank < nproc; ++rank ) {
          wait( pids[rank] );
      }
      

      【讨论】:

      • 我知道已经有一段时间了,但我有一个类似的练习,尽管我必须使用 exec。除了我想在每次分叉后使用的 2 个描述符之外,我是否需要关闭所有描述符?
      • 你可以尝试两种方法,看看会发生什么:)
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-06-20
      • 2019-09-02
      • 2021-03-30
      相关资源
      最近更新 更多