Ответ
fork() — это системный вызов в Unix-подобных операционных системах (Linux, macOS, BSD), который создаёт новый процесс. Новый процесс (дочерний) является почти точной копией процесса, который его вызвал (родительский). Оба процесса продолжают выполнение со следующей инструкции после fork().
Ключевые характеристики:
- Копирование: Дочерний процесс получает копию адресного пространства (памяти), таблицы файловых дескрипторов и других атрибутов родителя.
- Различие PID: Дочерний процесс имеет уникальный идентификатор процесса (PID), отличный от родительского.
- Возвращаемое значение: Это основной способ отличить процессы:
- В родительском процессе
fork()возвращает PID дочернего процесса (положительное число). - В дочернем процессе
fork()возвращает 0. - В случае ошибки возвращается -1.
- В родительском процессе
Типичный паттерн использования в C:
#include <stdio.h>
#include <unistd.h>
#include <sys/wait.h>
int main() {
pid_t pid = fork(); // Создаём новый процесс
if (pid == -1) {
perror("fork failed");
return 1;
}
if (pid > 0) {
// Код выполняется в РОДИТЕЛЬСКОМ процессе
printf("Parent: My PID is %d. Child's PID is %dn", getpid(), pid);
int status;
wait(&status); // Ожидаем завершения дочернего процесса
printf("Parent: Child process has finished.n");
} else {
// Код выполняется в ДОЧЕРНЕМ процессе (pid == 0)
printf("Child: My PID is %d. My parent's PID is %dn", getpid(), getppid());
// Здесь можно, например, выполнить другую программу с exec()
sleep(1); // Имитация работы
printf("Child: Exiting.n");
}
return 0;
}
Зачем это нужно в DevOps/администрировании?
- Демонизация: Демоны (фоновые службы) часто создаются через
fork(). Родительский процесс завершается, а дочерний продолжает работу под управлениемinit/systemd. - Параллелизм: Веб-серверы (например, Apache в prefork MPM) используют
fork()для создания пула процессов, каждый из которых обрабатывает отдельные HTTP-запросы. - Запуск внешних команд: Оболочка (bash) использует
fork()+exec()для запуска любой команды пользователя.
Ответ 18+ 🔞
Давай разберём эту штуку, а то некоторые думают, что fork() — это какая-то вилка для еды. Ёпта, нет же.
Представь себе, ты сидишь, такой, в терминале, и у тебя есть один процесс — это ты сам. И вот ты вызываешь fork(). Что происходит? Твой процесс берет и клонирует себя самого, блядь. Получается два абсолютно одинаковых чувака в памяти, как близнецы после копипаста. Один — родитель, второй — его дитё, дочерний процесс.
Вот ключевой момент, удивление пиздец: после клонирования они оба продолжают выполнять программу с одной и той же строчки — той, что сразу после fork(). Как же им понять, кто есть кто? А вот тут хитрая жопа системы: функция fork() возвращает разное значение в каждом из процессов.
Смотри на код, он всё объясняет:
pid_t pid = fork(); // Вот тут магия и случается
if (pid == -1) {
// На этом месте всё накрылось медным тазом. Ошибка, процесс не создался.
perror("fork failed");
return 1;
}
if (pid > 0) {
// Ага! Сюда попадает РОДИТЕЛЬСКИЙ процесс.
// Ему система любезно сообщила PID (идентификатор) его новорождённого отпрыска.
printf("Parent: My PID is %d. Child's PID is %dn", getpid(), pid);
// Тут он может, например, ждать, пока дитё закончит свои дела (wait()).
} else {
// А сюда — внимание! — попадает ДОЧЕРНИЙ процесс.
// Ему `fork()` вернула НОЛЬ. Да, ноль, нихуя себе. Так он понимает, что он — копия.
printf("Child: My PID is %d. My parent's PID is %dn", getpid(), getppid());
// И тут он может делать что угодно: спать, считать, или вообще заменить себя другой программой (exec()).
}
Зачем этот цирк нужен тебе, как админу или девопсу?
-
Демоны, блядь. Знаешь, как создаются фоновые службы? Почти всегда через
fork(). Родительский процесс просто откидывается, а дочерний продолжает жить своей жизнью, уже как самостоятельный демон под крылом systemd. Сам от себя охуел и стал службой. -
Веб-серверы. Старый добрый Apache (в режиме prefork) — это ебушки-воробушки. Он при старте делает
fork()несколько раз и создаёт пул готовых к работе процессов-копий. Приходит запрос — свободный процесс из пула его обрабатывает. Всё параллельно, без всяких там потоков. -
Любая команда в bash. Когда ты пишешь
ls -la, что делает оболочка? Она делаетfork(), создаёт своего клона, а тот клон сразу же делаетexec()и заменяет себя программойls. Родительский bash ждёт, покаlsотработает. Вот и вся магия, ёпта.
Короче, fork() — это фундаментальный кирпич, на котором построено овердохуища всего в Unix-мире. Не понял — перечитай, пока не дойдёт. Без этого никуда.