fork()
создает дочерний процесс путем дублирования вызывающего процесса, и он разделяет процесс на две части с точки, которую он вызывает. Дочерний и родительский процессы выполняются в отдельных пространствах памяти 1) . Во время fork()
оба пространства памяти имеют одинаковое содержимое. Это означает, что значение переменных в дочернем процессе совпадает со значением родительского процесса во время fork()
.
В первой итерации цикла for
:
pid[i] = fork();
// this will create child process and both parent and child process proceed with next statement
if ( pid[i] == 0){ // only child process will enter to this if block
printf("[child] pid %d from [parent] pid %d\n",getpid(),getppid());
}
Вывод на печать:
[child] pid 11310 from [parent] pid 11309
После выполнения тела цикла for
значение переменной управления цикла i
будет увеличиваться в адресном пространстве родительского и дочернего процессов из-за i++
.
Итак, во второй итерации значение i
равно 1
как в родительском, так и в дочернем адресном пространстве.
Теперь и родительский (PID: 11309)
, и дочерний (PID: 11310)
будут выполнять тело цикла for
, и оба будут создавать дочерний процесс. Вот почему дочерний процесс (PID: 11310)
создает другого потомка (PID: 11312)
.
11309----- --|
| | |---------> First iteration
11310 | --| --|
| | |---> Second iteration
11312 11311 --|
На третьей итерации значение i
будет 2
во всех процессах 4
, а условие цикла i<2
приведет к false
, и весь процесс завершится.
В вашем коде серьезная проблема - что произойдет, если родительский процесс завершится и завершится до дочернего процесса?
В этом случае дочерний процесс станет потерянным процессом , и вы можете получить родительский PID как 1
вместо исходного идентификатора родительского процесса, потому что потерянный процесс может быть переименован в init процесс, который обычно назначается PID 1
.
Чтобы преодолеть эту проблему, вы должны заставить родителя дождаться всех дочерних процессов перед выходом.
#include <stdio.h>
#include <sys/wait.h>
#include <unistd.h>
int main(void) {
pid_t pid;
// You can take number of child process to be create as input from user
for (int i = 0; i < 2; i++) {
pid = fork();
if (pid == 0) {
printf("[child] pid %d from [parent] pid %d\n", getpid(), getppid());
break;
}
}
if (pid != 0) {
int cpid;
int status;
while ((cpid = wait(&status)) > 0)
printf("Parent (%d): child (%d) exited with status 0x%.4x\n", (int)getpid(), cpid, status);
}
return 0;
}
1) Существует концепция, называемая Copy-on-Write , которая представляет собой оптимизацию, при которой таблицы страниц настраиваются таким образом, чтобы родительский и дочерний процессы начинали совместно использовать одну и ту же память и только страницы, на которые записан какой-либо процесс, копируются при необходимости. Это означает, что и родительский, и дочерний процессы совместно используют копии одних и тех же данных, и как только один из них выполняет запись, копия создается, и любое изменение в памяти одного процесса не видно в другом.