Ответ
В Linux для создания нового процесса традиционно используется комбинация двух системных вызовов: fork() и exec().
fork(): Создает почти точную копию (дочерний процесс) вызывающего процесса (родительского). Дочерний процесс получает копию памяти, файловых дескрипторов и других атрибутов. Для оптимизации используется механизм Copy-On-Write (COW): память физически копируется только при попытке записи.exec()семейство (например,execve): Заменяет текущий образ процесса (код, данные, стек) новым исполняемым файлом, загружаемым с диска. Этот вызов обычно выполняется в дочернем процессе послеfork(), чтобы запустить другую программу.
Типичная последовательность в оболочке (shell) или демоне:
#include <unistd.h>
#include <sys/wait.h>
pid_t pid = fork(); // Создаем копию процесса
if (pid == 0) {
// Код выполняется в дочернем процессе
char *args[] = {"/bin/ls", "-l", NULL};
execve(args[0], args, NULL); // Заменяем образ на /bin/ls
// Если execve вернул управление - это ошибка
_exit(EXIT_FAILURE);
} else if (pid > 0) {
// Код выполняется в родительском процессе
int status;
waitpid(pid, &status, 0); // Ожидаем завершения дочернего процесса
}
clone(): Более гибкий низкоуровневый вызов, на котором основаныfork()и механизмы создания потоков (threads). Позволяет точно контролировать, какие ресурсы (память, таблица файлов, пространство имен) будут разделяться между родителем и потомком. Именноclone()с определенными флагами используется для создания контейнеров (namespaces, cgroups).
С точки зрения DevOps, понимание этих вызовов важно для отладки проблем с порождением процессов в контейнерах, написания своих демонов или скриптов мониторинга.