Понимание fork () в цикле for и использование exit () - PullRequest
0 голосов
/ 17 мая 2018

Эй, у меня вопрос по поводу fork() и как он ведет себя в цикле for.

У меня спрашивают:

Создать родительский процесс, который создает 10 дочерних процессов, каждый из которых печатает фактическое значение i в цикле for. Этот код правильный?

int i;

for(i=0;i < 10;i++){
  if(fork()==0){
     print(i);
  }
  exit(0);
}

Насколько я понимаю, этот фрагмент кода создает на каждой итерации цикла родительский и дочерний элементы, где родительский элемент завершается напрямую, а дочерний элемент печатает i;

Итак, чтобы только один родитель и 10 детей печатали i, я должен обернуть exit(0) следующим образом:

int i;
int p;

for(i=0;i < 10;i++){
  if((p=fork())==0){
     print(i);
  }
  if(p > 0){
  exit(0);
  }
}

Может ли кто-нибудь подтвердить или это, если это правильно, или помочь мне лучше понять, если это неправильно.

Спасибо:)

1 Ответ

0 голосов
/ 22 мая 2018

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

В вашем первом фрагменте у вас действительно есть только один родитель. Единственная проблема, она заканчивается на самой первой итерации. :)

Посмотрите: i = 0, теперь у нас есть только родительский процесс (назовите его P). P вводит fork() и оставляет его дважды: в P (возвращая PID дочернего элемента) и во вновь созданном дочернем элементе C0 (возвращая 0). Тогда, согласно утверждению if, C0 выводит 0, P ничего не делает. Тогда пути выполнения сходятся, и оба P и C0 выходят. Теперь у нас нет наших процессов вообще.

Тело цикла второго фрагмента можно переписать следующим образом:

p = fork();
if (p == 0) {
    print(i);
}
if (p > 0) {
    exit(0);
}

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

Вам просто нужно переписать его так:

for(i = 0; i < 10; i++) {
    p = fork();
    if (p == 0) {
        print(i);
        exit(0);
    }
    // In fact, you should place waitpid(...) somewhere here,
    // otherwise the child will become a so called zombie process 
    // after its  termination.
    // Only after parent termination they all will be
    // finally recycled by init (PID 1) generally using up your system's 
    // resources for indefinite time
}

Теперь у вас есть P, который создает C0. C0 печатает его номер и сразу же выходит, в то время как P просто переходит к следующей итерации цикла, создавая C1, который так же, как C0 печатает его номер и выходит, и так далее. AFAIK это то, что изначально просили.

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

...