Системный вызов fork () используется для создания процессов. Он не принимает аргументов и возвращает идентификатор процесса. Цель fork () - создать новый процесс, который становится дочерним процессом вызывающей стороны. После создания нового дочернего процесса оба процесса выполнят следующую инструкцию после системного вызова fork (). Поэтому мы должны отличать родителя от ребенка. Это можно сделать, протестировав возвращаемое значение fork ():
Если fork () возвращает отрицательное значение, создание дочернего процесса завершилось неудачно.
fork () возвращает ноль недавно созданному дочернему процессу.
fork () возвращает положительное значение, идентификатор процесса дочернего процесса, родителю. Возвращенный идентификатор процесса имеет тип pid_t, определенный в sys / types.h. Обычно идентификатор процесса является целым числом. Более того, процесс может использовать функцию getpid () для получения идентификатора процесса, назначенного этому процессу.
Поэтому после системного вызова fork () простой тест может определить, какой процесс является дочерним. Обратите внимание, что Unix сделает точную копию адресного пространства родителя и передаст ее ребенку. Поэтому родительский и дочерний процессы имеют отдельные адресные пространства.
Давайте разберемся с этим на примере, чтобы прояснить вышесказанное. Этот пример не различает родительский и дочерний процессы.
#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#define MAX_COUNT 200
#define BUF_SIZE 100
void main(void)
{
pid_t pid;
int i;
char buf[BUF_SIZE];
fork();
pid = getpid();
for (i = 1; i <= MAX_COUNT; i++) {
sprintf(buf, "This line is from pid %d, value = %d\n", pid, i);
write(1, buf, strlen(buf));
}
}
Предположим, что вышеуказанная программа выполняется до точки вызова fork ().
Если вызов fork () выполнен успешно, Unix сделает две идентичные копии адресных пространств, одно для родительского и другое для дочернего.
Оба процесса начнут выполнение с следующего оператора после вызова fork (). В этом случае оба процесса начнут выполнение с присваивания
pid = .....;
Оба процесса начинают свое выполнение сразу после системного вызова fork (). Поскольку оба процесса имеют идентичные, но отдельные адресные пространства, переменные, инициализированные перед вызовом fork (), имеют одинаковые значения в обоих адресных пространствах. Поскольку каждый процесс имеет свое собственное адресное пространство, любые модификации будут независимы от других. Другими словами, если родитель изменяет значение своей переменной, модификация будет влиять только на переменную в адресном пространстве родительского процесса. Другие адресные пространства, созданные вызовами fork (), не будут затронуты, даже если они имеют идентичные имена переменных.
В чем причина использования write, а не printf? Это потому, что printf () "буферизован", что означает, что printf () сгруппирует выходные данные процесса вместе. При буферизации вывода для родительского процесса дочерний процесс может также использовать printf для распечатки некоторой информации, которая также будет буферизована. В результате, поскольку вывод не будет немедленно отправлен на экран, вы можете не получить правильный порядок ожидаемого результата. Хуже того, выходные данные двух процессов могут смешиваться странным образом. Чтобы преодолеть эту проблему, вы можете использовать «небуферизованную» запись.
Если вы запустите эту программу, вы можете увидеть на экране следующее:
................
This line is from pid 3456, value 13
This line is from pid 3456, value 14
................
This line is from pid 3456, value 20
This line is from pid 4617, value 100
This line is from pid 4617, value 101
................
This line is from pid 3456, value 21
This line is from pid 3456, value 22
................
Идентификатор процесса 3456 может быть тот, который назначен родителю или ребенку. Из-за того, что эти процессы выполняются одновременно, их выходные строки смешиваются довольно непредсказуемым образом. Более того, порядок этих строк определяется планировщиком ЦП. Следовательно, если вы снова запустите эту программу, вы можете получить совершенно другой результат.