Какие сигналы бывают в Linux?
Комментарии (1)
Ответ сгенерирован нейросетью и может содержать ошибки
Сигналы в Linux
Сигналы — это асинхронные уведомления, отправляемые операционной системой процессам для обработки определенных событий. Это механизм inter-process communication (IPC) на уровне ОС.
Основные понятия
Сигнал — это просто число (от 1 до 31 в базовом наборе). Когда процесс получает сигнал, он прерывается и выполняет заранее определенный обработчик.
import signal
import time
import sys
# Определение обработчика сигнала
def signal_handler(signum, frame):
print(f"Received signal {signum}")
sys.exit(0)
# Регистрация обработчика
signal.signal(signal.SIGTERM, signal_handler)
# Теперь при получении SIGTERM выполнится signal_handler
while True:
time.sleep(1)
Основные сигналы (POSIX)
1. SIGTERM (15) - Завершить процесс (graceful shutdown)
import signal
import time
def graceful_shutdown(signum, frame):
print("Graceful shutdown initiated...")
# Очистить ресурсы
cleanup_resources()
print("Cleanup complete. Exiting.")
exit(0)
signal.signal(signal.SIGTERM, graceful_shutdown)
def cleanup_resources():
print("Closing database connections...")
print("Saving state...")
time.sleep(1)
# При kill <pid> (по умолчанию SIGTERM) выполнится graceful_shutdown
while True:
time.sleep(1)
Использование: kill <pid> отправляет SIGTERM. Процесс может обработать и завершиться красиво.
2. SIGKILL (9) - Принудительное завершение (нельзя перехватить!)
import signal
# ❌ SIGKILL нельзя перехватить
try:
signal.signal(signal.SIGKILL, signal_handler) # ValueError!
except ValueError as e:
print(f"Cannot handle SIGKILL: {e}")
Использование: kill -9 <pid> - ядро немедленно завершает процесс, без возможности очистки.
3. SIGINT (2) - Interrupt (Ctrl+C)
import signal
import time
def handle_interrupt(signum, frame):
print("\nKeyboardInterrupt received!")
raise KeyboardInterrupt()
signal.signal(signal.SIGINT, handle_interrupt)
print("Press Ctrl+C to interrupt")
try:
while True:
time.sleep(1)
except KeyboardInterrupt:
print("Process interrupted gracefully")
Использование: Нажать Ctrl+C в терминале.
4. SIGUSR1 и SIGUSR2 (10, 12) - Пользовательские сигналы
import signal
import os
def handle_usr1(signum, frame):
print("Received SIGUSR1 - do something")
def handle_usr2(signum, frame):
print("Received SIGUSR2 - do something else")
signal.signal(signal.SIGUSR1, handle_usr1)
signal.signal(signal.SIGUSR2, handle_usr2)
print(f"Process ID: {os.getpid()}")
print("Waiting for signals...")
while True:
pass
Использование: kill -USR1 <pid> или kill -USR2 <pid> для кастомных действий.
5. SIGCHLD (17) - Дочерний процесс завершился
import signal
import os
import time
def handle_child(signum, frame):
# Получить информацию о завершенном процессе
try:
while True:
child_pid, status = os.waitpid(-1, os.WNOHANG)
if child_pid == 0:
break
print(f"Child process {child_pid} exited with status {status}")
except OSError:
pass
signal.signal(signal.SIGCHLD, handle_child)
for i in range(3):
pid = os.fork()
if pid == 0: # Дочерний процесс
print(f"Child {i} working...")
time.sleep(1)
exit(0)
else: # Родительский процесс
print(f"Started child {pid}")
while True:
time.sleep(1)
6. SIGHUP (1) - Разорвано соединение (hangup)
import signal
import sys
def handle_hup(signum, frame):
print("Terminal disconnected - reloading config")
reload_config()
signal.signal(signal.SIGHUP, handle_hup)
def reload_config():
print("Configuration reloaded")
# Используется для перезагрузки конфига без перезапуска
# kill -HUP <pid>
Использование: При отключении терминала или для перезагрузки конфига.
7. SIGSTOP (19) и SIGCONT (18) - Остановка и возобновление
import signal
import time
# SIGSTOP нельзя перехватить - процесс просто замирает
# kill -STOP <pid> # Процесс паузируется
# kill -CONT <pid> # Процесс продолжает работу
print("Process running...")
while True:
print(time.time())
time.sleep(1)
8. SIGALRM (14) - Таймер
import signal
import time
def timeout_handler(signum, frame):
print("Time limit exceeded!")
raise TimeoutError("Operation took too long")
signal.signal(signal.SIGALRM, timeout_handler)
# Установить таймер на 5 секунд
signal.alarm(5)
try:
print("Doing something...")
time.sleep(10) # Будет прервано в 5 секунд
except TimeoutError:
print("Operation timed out")
finally:
signal.alarm(0) # Отменить таймер
9. SIGSEGV (11) - Segmentation Fault
import signal
def handle_segfault(signum, frame):
print("Segmentation fault occurred!")
# Только для логирования - процесс все равно упадет
exit(1)
signal.signal(signal.SIGSEGV, handle_segfault)
# Обычно возникает при нарушении памяти
# В Python редко, но может быть в C расширениях
10. SIGPIPE (13) - Broken pipe
import signal
import sys
# Игнорировать разорванные pipe (для корректной работы piping)
signal.signal(signal.SIGPIPE, signal.SIG_DFL)
# Используется в команды типа: python script.py | grep something
Полный список сигналов
import signal
print("Signal numbering:")
for name, num in sorted([(n, getattr(signal, n))
for n in dir(signal)
if n.startswith(SIG) and not n.startswith(SIG_)],
key=lambda x: x[1]):
print(f"{name}: {num}")
# Вывод:
# SIGHUP: 1
# SIGINT: 2
# SIGQUIT: 3
# SIGILL: 4
# SIGTRAP: 5
# SIGABRT: 6
# SIGBUS: 7
# SIGFPE: 8
# SIGKILL: 9
# SIGUSR1: 10
# SIGSEGV: 11
# SIGUSR2: 12
# SIGPIPE: 13
# SIGALRM: 14
# SIGTERM: 15
# ...
Отправка сигналов из командной строки
# Список всех сигналов
kill -l
# Отправить SIGTERM (по умолчанию)
kill <pid>
# Отправить конкретный сигнал
kill -SIGTERM <pid>
kill -15 <pid>
kill -SIGKILL <pid>
kill -9 <pid>
# Отправить SIGUSR1
kill -USR1 <pid>
# Для текущего процесса
kill -STOP $$ # Остановить
kill -CONT $$ # Продолжить
Практический пример - корректное завершение сервера
import signal
import time
import sys
from http.server import HTTPServer, BaseHTTPRequestHandler
class MyHandler(BaseHTTPRequestHandler):
def do_GET(self):
self.send_response(200)
self.send_header("Content-type", "text/plain")
self.end_headers()
self.wfile.write(b"Hello World")
server = HTTPServer(("localhost", 8000), MyHandler)
def graceful_shutdown(signum, frame):
print("\nShutting down gracefully...")
server.shutdown()
print("Server stopped")
sys.exit(0)
# Обработать SIGTERM и SIGINT
signal.signal(signal.SIGTERM, graceful_shutdown)
signal.signal(signal.SIGINT, graceful_shutdown)
print("Server running on http://localhost:8000")
print("Press Ctrl+C to stop gracefully")
server.serve_forever()
Таблица важных сигналов
| Сигнал | Номер | Описание | Перехватимый |
|---|---|---|---|
| SIGTERM | 15 | Graceful завершение | ✅ Да |
| SIGKILL | 9 | Принудительное завершение | ❌ Нет |
| SIGINT | 2 | Ctrl+C | ✅ Да |
| SIGUSR1 | 10 | Пользовательский | ✅ Да |
| SIGUSR2 | 12 | Пользовательский | ✅ Да |
| SIGCHLD | 17 | Дочерний упал | ✅ Да |
| SIGHUP | 1 | Hangup | ✅ Да |
| SIGSTOP | 19 | Остановить | ❌ Нет |
| SIGCONT | 18 | Продолжить | ✅ Да |
| SIGPIPE | 13 | Broken pipe | ✅ Да |
Лучшие практики
- SIGTERM для graceful shutdown - обработай и заверши красиво
- Никогда не используй SIGKILL если есть альтернатива - потеря данных
- Обработчик должен быть быстрым - не делай в нем долгих операций
- Используй signal.pause() для ожидания сигналов - экономит CPU
- Не игнорируй SIGCHLD в многопроцессных приложениях
- В многопоточных приложениях - обработка сигналов сложнее