Выполнение процесса: почему выходные данные fork () находятся в таком порядке? - PullRequest
0 голосов
/ 13 октября 2018

Я делаю домашнюю работу по операционной системе 101 и копаю код на Си.Я новичок в C и Linux, поэтому у меня есть этот, возможно, необычный вопрос.Мне пришлось изучить программу на C, чтобы выяснить, сколько процессов она запускает.Поэтому я много читал и возился с оригинальным кодом, чтобы ответить на все вопросы.

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

int main (void) {
   printf("Start ID %d\n\n", getpid());

   printf("1.fork() from ");   
   printf("ID: %d\n", getpid());
   fflush(stdout);
   fork();

   printf("2.fork() from ");
   printf("ID: %d my parent is ID %d\n", getpid(), getppid());   
   fflush(stdout);
   fork();

   printf("3.fork() from ");
   printf("ID: %d my parent is ID %d\n", getpid(), getppid());  
   fflush(stdout);
   fork();

   sleep(2);   
   printf("%d finished. Good Night!\n", getpid());
   return EXIT_SUCCESS;
}

Есть одна вещь, которую я не понимаю.Почему выходные данные printf () перед вилками в следующем порядке:

1.fork() from ID: 3124
2.fork() from ID: 3124 my parent is ID 2215
3.fork() from ID: 3124 my parent is ID 2215
3.fork() from ID: 3126 my parent is ID 3124
2.fork() from ID: 3125 my parent is ID 3124
3.fork() from ID: 3125 my parent is ID 3124
3.fork() from ID: 3129 my parent is ID 3125

Я ожидал бы

1.fork() from ID: 3124
2.fork() from ID: 3124 my parent is ID 2215
3.fork() from ID: 3124 my parent is ID 2215
2.fork() from ID: 3125 my parent is ID 3124
3.fork() from ID: 3125 my parent is ID 3124
3.fork() from ID: 3126 my parent is ID 3124 
3.fork() from ID: 3125 my parent is ID 3124
3.fork() from ID: 3129 my parent is ID 3125

, потому что PID 3124 запускает PID 3125 с первой fork (), обаеще два дочерних процесса со вторым и так далее.Разве процессор не выполняет процессы в том порядке, в котором они были созданы?Это не часть моей домашней работы, но мне все равно любопытно.

Ответы [ 2 ]

0 голосов
/ 13 октября 2018

Вы не можете точно определить, какой процесс будет выполнен первым.Как и HackerBoss заявил, что printf также может влиять на этот порядок.

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

printf("2.fork() from ");

На этом этапе есть два направления:

  1. Фатер 3124 вызывает printf
  2. Child 3125 вызывает printf

Поскольку printf требует I/O scheduling, это зависит от process priority и resource state (тамэто может быть другой процесс, уже использующий ресурс, что делает его busy resource).

Таким образом, похоже, что в вашей программе отец 3124 сначала получает доступ к ресурсу и продолжает выполнение до следующего форка, где рождается ребенок 3126.

На этом этапе возникает один и тот же вопрос: в каком направлении мне идти?Следующая инструкция:

printf("3.fork() from ");

Направления:

  1. Fater 3124 вызывает printf
  2. Child 3126 вызывает printf

Из вашей программы похоже, что первый процесс, который вызывает ее, является дочерним 3126.

Так что на самом деле printf не гарантирует вам порядок генерации процесса.Поскольку прозрачно, как работает I/O scheduling, лучшим способом было бы сохранить значение в конкретном адресе, отличном для каждого процесса, заключив fork в оператор if:

pid=fork();
if (pid == 0) {
    //child process
} else {
    //father process
}

Таким образом, вы сможете лучше понять, что делает process scheduler, поскольку на самом деле это может быть process scheduler, который запускает дочерний элемент перед другим, существует множество алгоритмов планирования.На этом этапе OS, который вы используете, также влияет на порядок выполнения процесса, в зависимости от используемого алгоритма.

0 голосов
/ 13 октября 2018

Вывод операторов printf может варьироваться от запуска к выполнению, поскольку один разветвленный процесс может завершиться быстрее, чем другой.В этих случаях полезно нарисовать диаграмму дерева ветвей, чтобы определить все возможные случаи.В вашем случае вы можете гарантировать только то, что первый оператор печати будет печататься первым, второй оператор печати будет печататься перед третьим оператором печати в том же ответвлении, а второй оператор печати будет печататься перед третьим оператором печати во втором разветвленном дочернем элементе.,Это дает несколько возможных выходов.Технически, возможно, что один процесс не завершится через 2 секунды и напечатает свои выходные данные после одного из операторов завершения, хотя это маловероятно.

PS Хорошей практикой является перенос fork в if для проверки системных ошибок, но обычно это будет работать.

...