fork()、pipe() 和 exec() 进程创建和通信

Posted

技术标签:

【中文标题】fork()、pipe() 和 exec() 进程创建和通信【英文标题】:fork(), pipe() and exec() process creation and communication 【发布时间】:2011-07-02 22:02:09 【问题描述】:

我必须编写使用pipe() 创建进程的程序。

我的第一个任务是编写一个父进程,它使用fork() 函数生成四个子进程。

一旦fork() 成功,将子进程替换为另一个进程rover1, rover2, rover3, and rover4,尽管它们都具有相同的代码。

进程的功能如下。

    每个子进程最初都有自己的编号。它从父母那里收到一个新号码。使用以下公式,它会创建自己的新号码,如下所示并将其转发给父级:

    mynumber = (3 * mynumber + 4 * numberreceived)/7

    这个过程一直持续到父母发送系统稳定的消息。父级也有其初始编号。它接收所有孩子的数量并计算其新数量如下:

    mynumber = (3 * mynumber + <em>numbers sent by all the children</em>)/7

    父母会将此号码发送给它的所有孩子。这个过程将一直持续到父母发现它的号码不再变化。到时候它会告诉孩子系统已经稳定了。

这就是我所做的,但我的教授说我必须使用 exec() 来执行子进程并将子进程替换为另一个子进程。我不确定如何使用 exec()。你能帮我解决这个问题吗?

我只附加第一个子代。

// I included stdio.h, unistd.h stdlib.h and errno.h 
int main(void)

  // Values returned from the four fork() calls
  pid_t rover1, rover2, rover3, rover4;

  int parentnumber, mynumber1, mynumber2, mynumber3, mynumber4;

  int childownnumber1 = 0, status = 1, childownnumber2 = 0,
      childownnumber3 = 0, childownnumber4 = 0, numberreceived = 0;

  printf("Enter parent number: ");
  printf("%d", parentnumber);
  printf("Enter each children number");
  printf("%d %d %d %d", mynumber1, mynumber2, mynumber3, mynumber4);

  // Create pipes for communication between child and parent
  int p1[2], p2[2];
  // Attempt to open pipe
  if (pipe(p1) == -1) 
    perror("pipe call error");
    exit(1);
  
  // Attempt to open pipe
  if (pipe(p2) == -1) 
    perror("pipe call error");
    exit(1);
  

  // Parent process generates 4 child processes
  rover1 = fork();

  // if fork() returns 0, we're in the child process;
  // call exec() for each child to replace itself with another process
  if (rover1 == 0) 
    for(; numberreceived != 1; )   
      close(p1[1]); // Close write end of pipe
      close(p2[0]); // Close read end of second pipe

      // Read parent's number from pipe
      read(p1[0], &numberreceived, sizeof(int));

      if (numberreceived == 1) 
        // System stable, end child process
        close(p1[0]);
        close(p2[1]);
        _exit(0); // End child process
      

      mynumber1 = (int)((3*mynumber1 + 4*numberreceived)/7.0);

      printf("\nrover1 number: ");
      printf("%i", mynumber1);

      // Write to pipe
      write(p2[1], &mynumber1, sizeof(int));    
           
  
  /* Error:
   * If fork() returns a negative number, an error happened;
   * output error message
   */
  if (rover1 < 0) 
    fprintf(stderr,
            "can't fork, child process 1 not created, error %d\n",
            errno);
    exit(EXIT_FAILURE);
  

【问题讨论】:

子进程应该执行的功能是否包含在roverX 可执行文件中? 【参考方案1】:

exec 系列函数用于用新进程替换当前进程。注意replace这个词的使用。一旦调用了 exec,当前进程就消失了,新进程开始了。如果你想创建一个单独的进程,你必须先fork,然后exec子进程内的新二进制文件。

使用exec 函数类似于从命令行执行程序。要执行的程序以及传递给程序的参数在对exec 函数的调用中提供。

例如,下面的execcommand*等价于后面的shell命令:

execl("/bin/ls", "/bin/ls", "-r", "-t", "-l", (char *) 0);

/bin/ls -r -t -l

* 注意“arg0”是要执行的命令/文件名


由于这是家庭作业,因此对这个过程有一个很好的了解很重要。您可以先阅读有关 pipeforkexec 的文档并结合一些教程,以更好地理解每个步骤。

以下链接应该可以帮助您入门:

IBM developerWorks: Delve into UNIX process creation YoLinux Tutorial: Fork, Exec and Process control Pipe, Fork, Exec and Related Topics

【讨论】:

@jschmier- 感谢所有这些链接。我将使用上面的 exec 函数。【参考方案2】:

如果您应该使用exec,那么您应该将您的程序分成两个二进制文件。

基本上,现在由子进程执行的代码应该在第二个二进制文件中,并且应该使用exec 调用。

在调用exec 系列函数之一之前,您还需要使用dup2 将管道描述符重定向到新进程的标准输入/输出。这样,获得exec'd 的第二个二进制文件中的代码将不会知道管道,而只会读取/写入标准输入/输出。

还值得注意的是,您现在在子进程中使用的一些数据是通过fork 从父进程继承而来的。使用exec时,子级不会共享数据,也不会共享父级的代码,所以也许您也可以考虑通过管道传输所需的数据。

【讨论】:

以上是关于fork()、pipe() 和 exec() 进程创建和通信的主要内容,如果未能解决你的问题,请参考以下文章

linux下fork两子进程为啥只有一个读取到pipe的内容?

fork和exec函数

fork,wait和exec

fork,wait和exec

fork,exec,vfork和线程池

Linux下进程的创建(system(); fork(); exec*())