Концепция развилки: fork() Для порождения нового процесса предназначен системный вызов fork(), объявленный в заголовочном файле unistd.h следующим образом:
pid_t fork (void); Системный вызов fork() порождает процесс методом "клонирования". Это значит, что новый процесс является точной копией своего родителя и выполняет ту же самую программу. Это звучит странно, но попробуем разобраться во всем по порядку. Рассмотрим сначала небольшой пример (листинг 10.1)
Листинг 10.1. Пример fork1.c
#include #include int main (void)
{
fork ();
printf ("Hello World\n");
sleep (15);
return 0;
}
Вот что получилось:
Программа fork1 породила новый процесс, о чем свидетельствует вывод программы ps. Сразу после вызова fork() каждый процесс продолжил самостоятельно выполнять одну и ту же программу fork1. Этим и объясняется наличие двух приветствий "Hello World" в файле output
Чтобы в контексте программы отделить один процесс от другого, достаточно знать, что системный вызов fork() возвращает в текущем процессе PID порожденного потомка (или –1 в случае ошибки). А в новый процесс fork() возвращает 0.
Рассмотрим пример (листинг 10.2), в котором родительский и дочерний процессы выполняют разные действия.
Листинг 10.2. Пример fork2.c
#include #include #include int main (void)
{
pid_t result = fork();
if (result == -1) {
fprintf (stderr, "Error\n");
return 1;
}
if (result == 0)
printf ("I'm child with PID=%d\n", getpid ());
else
printf ("I'm parent with PID=%d\n", getpid ());
return 0;
}
Получилось следующее:
$ ./fork2 I'm child with PID=19414
I'm parent with PID=19413
В приведенном примере сообщение родителя могло бы появиться первым. Дело в том, что процессы в Linux работают на самом деле не одновременно. Ядро периодически дает возможность каждому процессу передать свой исполняемый код процессору (или процессорам, если их несколько). Эти переключения обычно происходят настолько быстро, что у нас создается иллюзия одновременной работы нескольких программ.
За переключение процессов отвечают специальные алгоритмы, находящиеся в ядре
Linux. Считается, что пользователи и программисты должны условно считать алгоритмы переключения процессов непредсказуемыми. Иными словами, процессы в
Linux работают независимо друг от друга. Подобная договоренность позволяет ядру Linux "интеллектуально" распределять системные ресурсы между процессами, повышая производительность системы в целом.
Рассмотрим пример (листинг 10.3), демонстрирующий "непредсказуемость" переключения процессов в Linux.