Почему эта функция создает так много дочерних процессов?

#c #process

#c #процесс

Вопрос:

Я написал этот код для того, чтобы вычислить факториал числа, используя процессы и pipe() . Я хотел передать результат от дочернего процесса дочернему процессу. Например, для создания calculate 5! основной, который является отцом, отправляет число 1 в канал. Затем создается первый дочерний процесс, который выполняет 1 * 2, затем он помещает в канал число 2, второй дочерний процесс выполняет 2 * 3, помещает результат в канал и т.д… Кроме того, я использую argv[1][0], думая, что мы запускаем программу следующим образом (./ex3 5), где 5 — это число, из которого мы хотели бы найти факториал. Однако после запуска программы я заметил, что было создано много дочерних процессов (я хотел только 4). Почему это?

 #include <stdio.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#include <stdlib.h>

int fd[2];
int w,count=2;

void child_creator(){
    pid_t child;
    child=fork();
    if (child==0) {
        close(fd[1]);
        read(fd[0],amp;w,sizeof(w));
        close(fd[0]);
        w=w*count;
        count  ;
        printf("I am child %d , my father is %d , the prod is %dn",getpid(),getppid(),w);
        sleep(1);

        close(fd[0]);
        write(fd[1],amp;w,sizeof(w));
        close(fd[1]);       
    }
}       

int main(int argc , char **argv){
    int fact=argv[1][0]-'0';
    pipe(fd);
    w=1;
    for (int i=0; i<fact-1; i  ){
         printf("this is i %dn", i);
        child_creator();
    }
    return 0;
}   
  

После предложенного ответа я попробовал этот код:

 #include <stdio.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#include <stdlib.h>

int fd[1000][2];
int w,count=1,j=0;

void child_creator(){
    pid_t child;
    j  ;
    pipe(fd[j]);
    child=fork();
    if (child==0) {
        close(fd[j-1][1]);
        read(fd[j-1][0],amp;w,sizeof(w));
        close(fd[j-1][0]);
        w=w*count;
        printf("I am child %d , my father is %d , the prod is %dn",getpid(),getppid(),w);
        sleep(1);

        close(fd[j-1][0]);
        write(fd[j][1],amp;w,sizeof(w));
        close(fd[j][1]);

        exit(0);        

    }

}       

int main(int argc , char **argv){
    int fact=argv[1][0]-'0';
    w=1;
    for (int i=0; i<fact-1; i  ){ 
     count  ;
     child_creator();
     sleep(2);
    }

    return 0;
}   
  

Комментарии:

1. Потому что ваши дочерние процессы тоже создают своих дочерних.

2. И родительский, и дочерний продолжают выполнение for цикла.

3. @EugeneSh. Как мне это исправить и получить тот же результат?

4. @maverick98 Подумайте, вернул ли ‘child_creator(..)’ дочерний pid, поэтому во внешнем цикле: if (child_creator() == 0) { break /* child doesn't get to loop again! */; } . Это лучше показывает поток и почему дочерний элемент также выполняет цикл «родители»? Множество вариантов для фактического решения таких..

5. Дочерний процесс может завершиться вместо возврата.

Ответ №1:

И родительский, и дочерний процесс возвращаются к for циклу в main() . Поскольку дочернему процессу не нужно ничего делать после записи результата, он должен просто завершить работу, а не возвращаться.

У вас также есть проблемы с обработкой дескрипторов файлов канала. Вы делаете это close(fd[1]) в начале дочернего процесса, но позже пытаетесь write(fd[1],amp;w,sizeof(w)) . Вы не можете выполнять запись в закрытый FD. Вам не нужно ничего закрывать, пока дочерний процесс не завершится, а выход из процесса автоматически закрывает все его файлы.

 void child_creator(){
    pid_t child;
    child=fork();
    if (child==0) {
        read(fd[0],amp;w,sizeof(w));
        w=w*count;
        count  ;
        printf("I am child %d , my father is %d , the prod is %dn",getpid(),getppid(),w);
        sleep(1);
        write(fd[1],amp;w,sizeof(w));
        exit(0);   
    }
}       
  

Комментарии:

1. Я также не уверен в использовании одного и того же канала для каждого дочернего процесса. Вы не можете быть уверены, что они будут записывать и считывать данные в нужном порядке.

2. @maverick98 после вашей правки ваш код все еще закрывается fd[1] перед попыткой записи в него…

3. @MichaelBeer Как я могу это исправить? Я удалил close(fd[1]); но когда я запускаю программу, она вообще ничего не печатает

4. Объявляйте массив каналов, создавайте новый канал перед каждой развилкой, и каждый дочерний канал использует соответствующий канал для связи со следующим в серии.

5. @Barmar Я пробовал то, что вы сказали, но, по-моему, я делаю что-то не так, я отредактировал сообщение с помощью нового кода