Как использовать несколько waitpid () с явными дочерними pid в качестве параметров для определенного порядка выполнения процесса - PullRequest
1 голос
/ 07 июля 2019

Работая с родительским процессом и двумя дочерними процессами, моя цель состоит в том, чтобы реализовать простой канал, который бы отправлял выходные данные дочернего элемента A на вход дочернего элемента B. Я хотел, чтобы это произошло до выполнения родительского кода. Наличие двух дочерних элементов и использование waitpid () x2 в родительском разделе приводит к зависанию. Мое намерение состоит в том, чтобы использовать первый аргумент waitpid (), чтобы указать каждого из двух потомков, которых нужно ждать. Насколько я понимаю, это допустимое использование waitpid ().

Я создал простой пример без трубы и только с одним дочерним элементом. Родитель использует waitpid () с дочерним pid в качестве первого аргумента. Это хорошо работает и подтверждает, что я правильно использую pid arg. Затем, вернувшись к исходному коду с двумя дочерними элементами (ниже), я попытался использовать -1 в качестве первого аргумента в каждом из waitpid (), так как я понимаю, что это более общий подход. Это все еще висит. Затем я подумал, что, возможно, поскольку дочерний процесс B ожидает выполнения дочернего процесса A, прежде чем он выполнит, к тому времени, когда родительский элемент дочернего процесса A его waitpid больше не будет изменять состояние, поэтому я попытался иметь только ожидание дочернего процесса B. Он все еще зависает. Я пытался добавить exit (0) в конец каждого блока кода каждого дочернего элемента, но я думаю, что это плохая идея, потому что тогда, когда достигается блок кода родительского элемента, дочерние элементы становятся зомби. Так что мой пробел в знаниях заключается в понимании того, когда именно дети меняют состояние и в какие моменты waitpid () может регистрировать эти изменения, а когда нет.

Система: Linux 5.1.15 и GCC 9.1.0 & bash 5.0.7 (1)

#include <unistd.h>
#include <sys/wait.h>
#include <stdio.h> 
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>
#include <stdlib.h>
#include <errno.h>

int main(){
  pid_t child_a, child_b;
  int fd_pipe[2];
  if(pipe(fd_pipe) == -1){
    fprintf(stderr, "pipe failed\n");
    perror(NULL);
  }  
  child_a = fork();
  if(child_a < 0){
    fprintf(stderr, "child_a fork failed\n");
    perror(NULL);
  }
  else if(child_a == 0){
    //child_a
    printf("child_a pid: %d\n", getpid());
    close(STDOUT_FILENO);
    dup(fd_pipe[1]);
    close(fd_pipe[0]);
    close(fd_pipe[1]);
    printf("test");
  }
  else{
    child_b = fork();
    if(child_b < 0){
      fprintf(stderr, "child_b fork failed\n");
      perror(NULL);
    } 
    else if(child_b == 0){
      //child_b
      pid_t wait_ret = waitpid(child_a, NULL, 0);
      printf("child_b pid: %d\n", getpid());
      close(STDIN_FILENO);
      dup(fd_pipe[0]);
      close(fd_pipe[1]);
      close(fd_pipe[0]);
      char str[5];
      scanf("%s",str);
      printf("%d %s %d\n",getpid(), str, getpid());
    }
    else {
    //parent
      pid_t wait_ret = waitpid(child_a, NULL, 0);
      wait_ret = waitpid(child_b, NULL, 0);
      printf("parent pid: %d\n", getpid());
    }
  }
}

Я ожидаю, что ребенок A объявит о себе с помощью PID, а затем ребенок B объявит о себе с помощью PID вместе с выданным по трубопроводу печатным «тестом». И тогда я ожидаю, что родитель объявит о себе. Вместо этого я получаю начальные отпечатки детей A и B, а затем зависаю.

1 Ответ

1 голос
/ 07 июля 2019

выполняется следующий предложенный код:

#include <unistd.h>
#include <sys/wait.h>
#include <stdio.h> 
//#include <sys/types.h>
//#include <sys/stat.h>
//#include <fcntl.h>
//#include <string.h>
#include <stdlib.h>
//#include <errno.h>

int main( void )
{
    pid_t child_a;
    pid_t child_b;
    int fd_pipe[2];

    if(pipe(fd_pipe) == -1)
    {
        perror( "pipe failed" );
        exit( EXIT_FAILURE );
    }  

    child_a = fork();
    if(child_a < 0)
    {
        perror( "child_a fork failed" );
        exit( EXIT_FAILURE );
    }

    else if(child_a == 0)
    {
        //child_a
        printf("child_a pid: %d\n", getpid());

        close(STDOUT_FILENO);
        dup(fd_pipe[1]);

        close(fd_pipe[0]);
        close(fd_pipe[1]);
        printf("test");
        exit( EXIT_SUCCESS );
    }

    else
    {  // parent 
        child_b = fork();

        if(child_b < 0)
        {
            perror( "child_b fork failed" );
            exit( EXIT_FAILURE );
        } 

        else if(child_b == 0)
        {
            //child_b
            printf("child_b pid: %d\n", getpid());

            close(STDIN_FILENO);
            dup(fd_pipe[0]);

            close(fd_pipe[1]);
            close(fd_pipe[0]);

            char str[5];
            if( scanf("%4s",str) != 1 )
            {
                fprintf( stderr, "scanf failed\n" );
                exit( EXIT_FAILURE );
            }

            printf("%d %s %d\n",getpid(), str, getpid());   
        }

        else 
        {
            //parent
            waitpid(child_a, NULL, 0);
            waitpid(child_b, NULL, 0);

            close(fd_pipe[1]);
            close(fd_pipe[0]);
            printf("parent pid: %d\n", getpid());
        }
    }
}

приводит к следующему выводу

child_b pid: 26137
child_a pid: 26136
26137 test 26137
parent pid: 26135

Примечание: не включайте заголовочные файлы, содержимое которых не используется.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...