Открыть сервис

Сигнал 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 →