Как иметь 3 вызова fork() и создать 6 процессов без использования цикла

#c #linux #operating-system

#c #linux #операционная система

Вопрос:

Мне было поручено создать ровно 6 процессов с использованием языка c и команды fork(), а затем перевести все 6 в режим ожидания с помощью sleep() на минуту или две. Сложнее всего то, что нам вообще не разрешено использовать какие-либо циклы, и всего 3 вызова fork() . Мне удалось успешно создать 8, но это слишком много. Итак, мне было интересно, можно ли разветвлять или уничтожать определенные процессы.Я попробовал кое-что, что видел здесь, но это дает мне 8 процессов, а не 6

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

int main()
{

/* fork a child process */
pid_t child = fork();
pid_t parent = getpid();


 fork(); //2
 if (fork() > 0) {//now we have 2 processes
     //only the parent calls this fork because of the if, so we have 3 processes
    fork(); //all 3 processes calls this fork, so we have 6 processes
    wait(NULL);
    printf("I am the child process");
    printf("my PID = %d ",child);
    printf("I am the parent process. My PID is %dn", parent);

     wait(NULL);
    
}
    else if (child < 0) { /* error occurred */
    fprintf(stderr, "Fork Failed");
    return 1;
}


}
  

я получаю:

 I am the child processmy PID = 22150 I am the parent process. My PID is 22149
I am the child processmy PID = 22150 I am the parent process. My PID is 22149
I am the child processmy PID = 0 I am the parent process. My PID is 22150
I am the child processmy PID = 22150 I am the parent process. My PID is 22149
I am the child processmy PID = 0 I am the parent process. My PID is 22150
I am the child processmy PID = 0 I am the parent process. My PID is 22150
I am the child processmy PID = 0 I am the parent process. My PID is 22150
I am the child processmy PID = 22150 I am the parent process. My PID is 22149
  

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

1. Возвращаемое значение fork() сообщает вам, находитесь ли вы в родительском или дочернем процессе, и (только в родительском), было ли разветвление успешным. Подробнее читайте его документацию. Вы можете использовать это для различения процессов, чтобы выбрать, какие из них должны развиваться дальше.

2. Вы вызываете fork 4 раза. Возможно, вы не намеревались вызывать fork при инициализации переменной child . Если вы удалите этот вызов, ваша логика кажется правильной, и вы получите 6 процессов, как и требовалось.

3. Но обратите внимание на двусмысленность во фразе «вызов fork 4 раза». В вашем коде есть 4 разных экземпляра токена «fork», но всего он вызывается 11 раз.

4. Хотя ваша программа выдает вам 8 строк вывода, у вас есть 12 процессов. Не все из них выдают выходные данные.

Ответ №1:

Вы можете получить дерево с 6 новыми процессами ( 1 исходный), создав третью вилку только в 3 из четвертых процессов, которые у вас будут после 1-го 2 вилки.

 #include <unistd.h>
#include <stdio.h>
/*
Process tree:
  /
 /
//
  

  /
  /
  
*/

int main()
{
    _Bool descended_from_parent, descended_from_child;
    pid_t pid;
    if(0>(pid=fork())) return perror("fork"),1;
    descended_from_parent = pid == 0;
    if(0>(pid=fork())) return perror("fork"),1;
    descended_from_child = pid == 0;
    if(!descended_from_parent || descended_from_child) if(0>(pid=fork())) return perror("fork"),1;
    sleep(60);
}
// run as `./a.out amp;` and then do `ps --forest` to see the process tree
  

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

1. Тогда @bruno, должно быть, неправильно понял это. Исправлено. Спасибо.

Ответ №2:

 #include <stdio.h>
#include <unistd.h>

int main(void) {
    int f1 = -1, f2 = -1, f3 = -1;
    printf("1 process running -- f1: %d; f2: %d; f3: %dn", f1, f2, f3);

    sleep(1); // try to prevent print lines mangling
    f1 = fork(); // assume it worked
    printf("2 processes running -- f1: %d; f2: %d; f3: %dn", f1, f2, f3);

    sleep(1); // try to prevent print lines mangling
    f2 = fork(); // assume it worked for the 2 running processes
    printf("4 processes running -- f1: %d; f2: %d; f3: %dn", f1, f2, f3);

    sleep(1); // try to prevent print lines mangling
    if ((f1 > 0) || (f2 > 0)) f3 = fork(); // assume it worked for the 3 selected processes
    printf("7 processes running -- f1: %d; f2: %d; f3: %dn", f1, f2, f3);

    return 0;
}
  

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

1. Вы не можете вызывать printf followed by fork без прерывания fflush и ожидать разумного результата. Вы не должны полагаться на буферизацию стандартного вывода. (Выполните это с обычным файлом для стандартного вывода, и вы увидите совсем другой результат, чем когда стандартный вывод является tty.)

Ответ №3:

Ваша логика просто прекрасна. Я подозреваю, что путаница связана с инициализацией переменной child , в которой вы вызываете fork в первый раз. Кроме того, ваш вывод нечетный, и вы не сообщаете о результатах для каждого процесса. Простой рефакторинг вашего кода на что-то более простое показывает, что ваша логика верна:

 #include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/wait.h>    
int
main(void)
{
        fork();
        if( fork() == 0 ) {
                fork();
        }
        printf("PID = %dn", getpid());
}
  

Приведенный выше в основном ваш код, и он выдает ровно 6 строк вывода, по желанию. Единственное реальное отличие заключается в том, что я удалил ложный первоначальный вызов fork и переместил printf в нужное место. В вашем коде у вас есть 4 процесса, когда в вашем комментарии утверждается, что их всего 2 (из-за ложной инициализации fork ), и все 4 из них снова разветвляются, чтобы сделать 8. Из этих 8 4 из них переформируются, чтобы дать вам в общей сложности 12, из которых только 8 печатают какие-либо выходные данные. (4, которые были разветвлены, и их новые дочерние элементы.) Однако выходные данные, которые они выдают, наиболее необычны и не отражают фактический pid процесса, записывающего выходные данные. Они просто показывают идентификаторы pid, которые были после начальной вилки при инициализации child .

Ответ №4:

Самый простой способ

 #include <stdio.h>
int main()
{
    fork() amp;amp; fork();
    fork();
    printf("%d %dn",getpid(),getppid());
    sleep(1);
}
  

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

1. Пожалуйста, добавьте некоторые пояснения к вашему ответу. В частности, в чем преимущество fork() amp;amp; fork(); более двух fork(); операторов?