fork(), pipe() and exec() process creation

2019-02-13 23:53发布

问题:

I have to write program that create process using pipe().

My first task is to write a parent process that generates four child processes using the fork() function.

Once the fork() is successful, replace the child process with another process rover1, rover2, rover3, and rover4, though all of them have the same code.

The function of the processes is as follows.

  1. Each child process is initially given its own number. It receives a new number from the parent. Using the following formula it creates its own new number as follows and forwards it to the parent:

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

  2. This process continues until the parent sends the message that the system is stable. The parent also has its initial number. It receives numbers of all the children and computes its new number as follows:

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

  3. The parent will send this number to all its children. This process will continue until the parent finds that its number is not changing anymore. At that time it will tell the children the system has become stable.

This is what I did but my professor said I have to use exec() to execute the child and replace child process with another child process. I am not sure how to use exec(). Could you please help me with this.

I am attaching only first child generation.

// 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);
  }
}

回答1:

The exec family of functions is used to replace the current process with a new process. Note the use of the word replace. Once exec is called, the current process is gone and the new process starts. If you want to create a separate process, you must first fork, and then exec the new binary within the child process.

Using the exec functions is similar to executing a program from the command line. The program to execute as well as the arguments passed to the program are provided in the call to the exec function.

For example, the following execcommand* is the equivalent to the subsequent shell command:

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

/bin/ls -r -t -l

* Note that "arg0" is the command/file name to execute


Since this is homework, it is important to have a good understanding of this process. You could start by reading documentation on pipe, fork, and exec combined with a few tutorials to gain a better understanding each step.

The following links should help to get you started:

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


回答2:

If you are supposed to use exec, then you should split your program into two binaries.

Basically, the code that now gets executed by the child should be in the second binary and should be invoked with exec.

Before calling one of the exec family of functions, you'll also need to redirect the pipe descriptors to the new process' standard input/output using dup2. This way the code in the second binary that gets exec'd won't be aware of the pipe and will just read/write to the standard input/output.

It's also worth noting that some of the data you are using now in the child process is inherited from the parent through the fork. When using exec the child won't share the data nor the code of the parent, so maybe you can consider transmitting the needed data through the pipe as well.