2014-04-01 51 views
0

因此,我一直在为我的OS类开发代码,在我的项目中,我必须在命令行中为每个文件创建一个新的子进程,孩子的父母。我们应该重新创建Unix的wc实用程序(我已经处理过这个部分)。用C语言为一个父类创建多个子进程

什么我迄今试图为:

  for(i=0; i<argcount; i++){ 
        int pid; 
        pid = fork(); 
        if(pid == 0){ 
          /* Child Process */ 
          /* Close read pipes */ 
          close(l_pipe[0]); 
          close(w_pipe[0]); 
          close(c_pipe[0]); 
          wc(lflag, wflag, cflag, filenames[i]); 
        } else { 
          /* Parent Process for piping */ 
          /* Close write pipes */ 
          close(l_pipe[1]); 
          close(w_pipe[1]); 
          close(c_pipe[1]); 

          /* Read from pipes */ 
          read(l_pipe[0], &buffer, sizeof(count_t)); 
          lines+=buffer; 

          read(w_pipe[0], &buffer, sizeof(count_t)); 
          words+=buffer; 

          read(c_pipe[0], &buffer, sizeof(count_t)); 
          bytes+=buffer; 
        } 
      } 

然而,本作也有孩子,这显然是错误的,创建多的父母。我不确定我应该在哪里分叉。我在子进程和父进程之间使用管道,并且我确信父进程需要read()的次数与子进程write()的次数一样多。

非常感谢您提供任何建议。

回答

1

除了通过Greg Hewgill在他answer提出的问题,我发现了以下问题:

  1. 你可以有循环叉子和运行子进程,而父部分简单地追溯到到循环的下一次迭代。
  2. 然后,您将有一个循环从管道读取。
  3. 在该循环之前,父进程将关闭所有三个管道的写入结束(否则它将永远不会在管道上看到EOF)。
  4. 从管道读取的循环应该依次从每个管道读取,而不是依次排空每个管道。
  5. 我假设你有count_t buffer; - 它有助于显示变量声明。如果你有某种类型的char buffer[sizeof(count_t)],那么你有各种各样的问题,无论大小。
  6. 当您在当前方案中创建第二个子项时,管道的写入结束全部关闭,因此第二个和后续的子项将无法向父项发送任何内容。您必须移动这三个调用来关闭管道的写入端,以便它位于循环之外。
  7. 您的管道必须位于全局变量中,以便wc函数可以使用它们。这不是世界的尽头,但是避免全局变量通常更加容易。这是一个二阶问题;你还有其他更重要的问题需要先解决。
  8. 如果您需要将尺寸与单个文件相关联,则需要进行更多簿记操作。目前,你只汇总总计。在这种情况下,您当前的同步设计可能是适当的。如果不这样做,你会让孩子在一次操作中写入一个PID或另一个ID号加上管道上的计数(以确保操作是原子的)。除非它们对于管道的内部缓冲区来说太大,否则各个写入操作不会交错,这对于几个整数不会造成问题。
+0

这是一个count_t缓冲区,当然。这看起来非常有帮助,我会玩你的建议。此外,我的wc()在stdin上打印它自己的计数,通过管道发送它们,并打印被调用的进程的PID。 – saturn

1

我注意到一些事情马上注意到。

  • 在你的孩子过程中的分支,你不叫wc()_exit()。这意味着你的孩子进程将循环并开始为更多的孩子分身。

  • 在您的父级进程分支中,您正等待刚刚生成的孩子的响应,然后继续创建下一个孩子。所以基本上你已经序列化了这个过程,并且不会利用多个过程。

+0

添加_exit()对我很有意义。至于第二个子弹,我没有足够的了解C来看到不同的做法。尽管谢谢你的帮助! – saturn

+0

一般而言:跟踪您在父流程中为子女创建的所有管道。分叉并开始所有的孩子。在分出所有数据后,从每个管道读取结果。 –

+0

@saturn:或者如果你觉得奇特,你可以使用系统调用['select'](http://linux.die.net/man/2/select)来阻塞,直到其中一个孩子有数据你,然后从那个管道读取。这在这里可能不重要,但是如果你开始做网络代码,或者长时间运行并行计算,它将会有所帮助。 – Linuxios