Сигнал SIGTERM¶
SIGTERM — это сигнал в операционных системах семейства Unix и совместимых с ними (включая Linux), предназначенный для вежливого завершения процесса. Он относится к стандартным сигналам POSIX и имеет номер 15. В отличие от сигнала SIGKILL (9), SIGTERM не принуждает операционную систему немедленно уничтожить процесс, а запрашивает его завершение, давая процессу возможность выполнить корректные действия по очистке ресурсов (закрыть файлы, сохранить данные, освободить память). SIGTERM является сигналом по умолчанию, отправляемым утилитами kill, pkill и killall, если не указан другой номер сигнала.
¶История и стандартизация
Сигнал SIGTERM был введён в ранних версиях Unix (AT&T Unix, 1970-е годы) как часть системы сигналов, предназначенных для межпроцессного взаимодействия и управления процессами. В спецификации POSIX.1-2001 (IEEE Std 1003.1) SIGTERM закреплён как обязательный сигнал с номером 15. Его поведение определено следующим образом: при получении SIGTERM процесс должен завершиться, но может перехватить, игнорировать или обработать сигнал, выполнив произвольные действия. В современных Unix-подобных системах (Linux, FreeBSD, macOS) SIGTERM остаётся стандартным механизмом для мягкого завершения процессов.
¶Номер сигнала
В большинстве Unix-подобных систем SIGTERM имеет номер 15. Это значение зафиксировано в заголовочном файле <signal.h> и в таблице сигналов ядра. Исключения редки: например, в некоторых исторических реализациях (System V Release 4) номер мог отличаться, но в современных системах (Linux, BSD, macOS) номер 15 является универсальным. В Linux номер SIGTERM определён константой SIGTERM (15) в /usr/include/asm-generic/signal.h.
¶Поведение по умолчанию
При получении SIGTERM процесс, не установивший собственный обработчик, завершается (terminate). Это означает, что ядро операционной системы прекращает выполнение процесса, освобождает его ресурсы (память, файловые дескрипторы, сокеты) и отправляет родительскому процессу статус завершения. Однако, в отличие от SIGKILL, процесс может перехватить SIGTERM с помощью функции signal() или sigaction() и выполнить код очистки (например, закрыть базы данных, записать логи, отправить уведомления). Если процесс игнорирует SIGTERM (устанавливает обработчик SIG_IGN), он не завершается, что может привести к «зависанию» процесса.
¶Отличие от других сигналов
¶SIGTERM (15) vs SIGKILL (9)
- SIGKILL — принудительное завершение, которое не может быть перехвачено, игнорировано или обработано. Ядро немедленно уничтожает процесс. SIGTERM — вежливый запрос, дающий процессу шанс на корректное завершение.
- SIGKILL не позволяет процессу выполнить cleanup-код; SIGTERM — позволяет.
- В системах управления процессами (например, systemd) сначала отправляется SIGTERM, и только если процесс не завершается в течение заданного таймаута (обычно 5–90 секунд), отправляется SIGKILL.
¶SIGTERM (15) vs SIGINT (2)
- SIGINT (Interrupt) обычно генерируется нажатием Ctrl+C в терминале и предназначен для прерывания текущей команды. SIGTERM — универсальный сигнал завершения, отправляемый программами или администратором.
- SIGINT также может быть перехвачен, но его семантика чаще связана с интерактивным прерыванием, а не с завершением службы.
¶SIGTERM (15) vs SIGQUIT (3)
- SIGQUIT (Quit) генерируется нажатием Ctrl+\ и, помимо завершения, создаёт дамп памяти (core dump) для отладки. SIGTERM не создаёт core dump.
¶Применение
¶Управление процессами в командной строке
kill -15 <PID>илиkill <PID>(по умолчанию отправляет SIGTERM).pkill -15 <имя_процесса>— отправляет SIGTERM всем процессам с указанным именем.killall -15 <имя_процесса>— аналогично.systemctl stop <service>— в systemd сначала отправляет SIGTERM, затем SIGKILL (если процесс не завершился).
¶Обработка в программах
Разработчики могут перехватывать SIGTERM для выполнения завершающих операций. Пример на языке C: ```c
¶include <signal.h>
¶include <stdio.h>
¶include <unistd.h>
void handle_sigterm(int sig) { printf("Получен SIGTERM, выполняю очистку...\n"); // Закрытие файлов, освобождение ресурсов _exit(0); }
int main() { signal(SIGTERM, handle_sigterm); while(1) { sleep(1); } return 0; } `` В скриптах на Bash SIGTERM может быть перехвачен с помощью trap: `bash trap "echo 'Завершение...'; exit 0" SIGTERM while true; do sleep 1; done ``
¶В контейнеризации и оркестрации
- Docker: команда
docker stop <контейнер>отправляет SIGTERM главному процессу контейнера (PID 1). Если процесс не завершается за 10 секунд (по умолчанию), отправляется SIGKILL. - Kubernetes: при завершении пода (pod) сначала отправляется SIGTERM, затем, после grace period (по умолчанию 30 секунд), — SIGKILL.
- Systemd: при остановке сервиса отправляется SIGTERM, и если процесс не завершается за
TimeoutStopSec(по умолчанию 90 секунд), — SIGKILL.
¶В системном администрировании
- При перезагрузке или выключении системы (команда
shutdown,reboot) init-система (systemd, SysV init) отправляет SIGTERM всем процессам, затем — SIGKILL. - При остановке демонов (веб-серверов, баз данных) рекомендуется сначала отправлять SIGTERM, чтобы они корректно завершили соединения и сохранили данные.
¶Критика и ограничения
- Ненадёжность: процесс может игнорировать SIGTERM, что приводит к необходимости использования SIGKILL. Некоторые программы (например, старые версии Apache) не перехватывали SIGTERM, что приводило к потере данных.
- Время ожидания: если процесс не обрабатывает SIGTERM быстро, система может принудительно завершить его через SIGKILL, что может вызвать повреждение данных (например, в базах данных).
- Сложность обработки: в многопоточных программах корректная обработка SIGTERM требует синхронизации потоков, что может быть нетривиально.
- Различия в POSIX: в некоторых реализациях (например, в Solaris) поведение SIGTERM может незначительно отличаться, но в Linux и BSD оно стандартно.
¶Интересные факты
- В Linux сигнал SIGTERM может быть отправлен процессу, даже если он находится в состоянии «зомби» (zombie), но ядро игнорирует его, так как зомби-процесс уже завершён.
- Некоторые демоны (например, sshd, nginx) перехватывают SIGTERM для «мягкого» перезапуска (graceful restart), а не для завершения.
- В языке Python модуль
signalпозволяет перехватывать SIGTERM, но в многопоточных приложениях обработчик выполняется только в главном потоке. - В контейнерах Docker, если главный процесс (PID 1) не перехватывает SIGTERM, контейнер может не завершиться корректно, что приводит к таймауту и принудительному SIGKILL.
¶Источники
- IEEE Std 1003.1-2017, «Signal Concepts», раздел «SIGTERM».
- Linux man pages: signal(7), kill(1), kill(2), sigaction(2).
- Документация systemd: «systemd.kill» (man 5 systemd.kill).
- Документация Docker: «docker stop» (официальная документация Docker Inc.).
- Документация Kubernetes: «Pod Lifecycle» (официальная документация Kubernetes).
- Стивенс, Р. «UNIX. Профессиональное программирование», 3-е издание, 2013.
BFOmetr — база данных и аналитика по компаниям России.
На главную BFOmetr →


