← Назад к вопросам
Как послать сигнал процессу?
1.0 Junior🔥 251 комментариев
#Linux и операционные системы
Комментарии (1)
🐱
claude-haiku-4.5PrepBro AI28 мар. 2026 г.(ред.)
Ответ сгенерирован нейросетью и может содержать ошибки
Как послать сигнал процессу
Что такое сигналы
Сигналы — это способ асинхронной коммуникации между процессами в Unix/Linux. Это программное прерывание, которое может заставить процесс выполнить определённое действие.
Основные сигналы:
- SIGTERM (15): мягкое завершение процесса (по умолчанию)
- SIGKILL (9): принудительное завершение (нельзя перехватить)
- SIGSTOP (19): остановить процесс (нельзя перехватить)
- SIGCONT (18): возобновить остановленный процесс
- SIGHUP (1): перезагрузить конфигурацию
- SIGUSR1, SIGUSR2: пользовательские сигналы для приложения
- SIGPIPE: попытка записи в закрытый pipe
1. Команда kill из shell
Простейший способ — использовать kill:
# Отправить SIGTERM (15) процессу с PID 1234
kill 1234
# Отправить конкретный сигнал
kill -SIGTERM 1234
kill -15 1234
# Принудительное завершение (SIGKILL)
kill -9 1234
# Остановить процесс
kill -SIGSTOP 1234
# Возобновить процесс
kill -SIGCONT 1234
# Отправить сигнал ВСЕМ процессам в процесс-группе
kill -15 -1234
2. Функция kill() в C/C++
#include <signal.h>
#include <unistd.h>
int kill(pid_t pid, int sig);
// Возвращает: 0 на успех, -1 на ошибку
Примеры:
#include <signal.h>
#include <unistd.h>
#include <iostream>
int main() {
pid_t target_pid = 5678; // PID процесса, которому отправляем сигнал
// Отправить SIGTERM
if (kill(target_pid, SIGTERM) == -1) {
perror("kill"); // Ошибка: нет прав, процесс не существует
return 1;
}
std::cout << "SIGTERM sent to process " << target_pid << std::endl;
// Отправить SIGUSR1
kill(target_pid, SIGUSR1);
// Проверить существует ли процесс (отправить сигнал 0)
if (kill(target_pid, 0) == -1) {
std::cout << "Process does not exist" << std::endl;
} else {
std::cout << "Process exists" << std::endl;
}
return 0;
}
3. Обработка сигналов в процессе
Процесс может перехватить сигнал и выполнить пользовательский код:
#include <signal.h>
#include <iostream>
#include <unistd.h>
bool shutdown_requested = false;
// Обработчик сигнала
void signal_handler(int sig) {
if (sig == SIGTERM) {
std::cout << "Received SIGTERM, shutting down gracefully..." << std::endl;
shutdown_requested = true;
} else if (sig == SIGUSR1) {
std::cout << "Received SIGUSR1, reloading config..." << std::endl;
// reload_config();
}
}
int main() {
// Зарегистрировать обработчик
signal(SIGTERM, signal_handler);
signal(SIGUSR1, signal_handler);
// Основной цикл
while (!shutdown_requested) {
std::cout << "Working..." << std::endl;
sleep(1);
}
std::cout << "Shutdown complete" << std::endl;
return 0;
}
4. Современный подход: sigaction()
signal() старый, есть проблемы. Используй sigaction():
#include <signal.h>
#include <iostream>
bool should_exit = false;
void handler(int sig) {
should_exit = true;
}
int main() {
struct sigaction sa;
sa.sa_handler = handler; // Функция-обработчик
sigemptyset(&sa.sa_mask); // Нет дополнительных блокируемых сигналов
sa.sa_flags = 0; // Стандартное поведение
// Регистрируем обработчик
sigaction(SIGTERM, &sa, nullptr);
sigaction(SIGINT, &sa, nullptr);
while (!should_exit) {
std::cout << "Running..." << std::endl;
sleep(1);
}
return 0;
}
5. Блокировка и отмена блокировки сигналов
Можно временно заблокировать определённые сигналы:
#include <signal.h>
int main() {
sigset_t set;
// Создать набор сигналов
sigemptyset(&set); // Пустой набор
sigaddset(&set, SIGTERM); // Добавить SIGTERM
sigaddset(&set, SIGUSR1); // Добавить SIGUSR1
// Заблокировать эти сигналы
sigprocmask(SIG_BLOCK, &set, nullptr);
// Теперь SIGTERM и SIGUSR1 не будут доставлены
// ... критичный код ...
// Разблокировать
sigprocmask(SIG_UNBLOCK, &set, nullptr);
return 0;
}
6. Отправка сигнала от одного процесса к другому
Пример: родитель отправляет сигнал потомку
#include <signal.h>
#include <unistd.h>
#include <iostream>
#include <sys/wait.h>
int main() {
pid_t pid = fork();
if (pid == 0) {
// Потомок: ловит сигналы
signal(SIGTERM, [](int) {
std::cout << "Child: Received SIGTERM\n";
exit(0);
});
while (true) {
std::cout << "Child working..." << std::endl;
sleep(1);
}
} else {
// Родитель: отправляет сигналы
sleep(3); // Дать потомку время на инициализацию
std::cout << "Parent: Sending SIGTERM to child " << pid << std::endl;
kill(pid, SIGTERM); // Отправить сигнал
wait(nullptr); // Дождаться завершения потомка
std::cout << "Parent: Child terminated" << std::endl;
}
return 0;
}
7. Сигнал от пользователя (Ctrl+C)
Когда пользователь нажимает Ctrl+C, система отправляет SIGINT:
#include <signal.h>
#include <iostream>
bool interrupted = false;
void handle_interrupt(int sig) {
std::cout << "\nCtrl+C pressed, shutting down..." << std::endl;
interrupted = true;
}
int main() {
signal(SIGINT, handle_interrupt);
while (!interrupted) {
std::cout << "Processing..." << std::endl;
sleep(1);
}
std::cout << "Cleanup completed" << std::endl;
return 0;
}
8. Практический пример: graceful shutdown
#include <signal.h>
#include <iostream>
#include <thread>
#include <atomic>
#include <vector>
class Server {
private:
std::atomic<bool> running{true};
std::vector<std::thread> worker_threads;
public:
static Server* instance;
Server() {
instance = this;
// Регистрируем обработчик
signal(SIGTERM, Server::handle_signal);
signal(SIGINT, Server::handle_signal);
}
static void handle_signal(int sig) {
std::cout << "Received signal " << sig << ", shutting down..." << std::endl;
if (instance) {
instance->running = false;
}
}
void run() {
for (int i = 0; i < 4; i++) {
worker_threads.emplace_back([this]() {
while (running) {
// выполнять работу
std::cout << "Working..." << std::endl;
sleep(1);
}
});
}
// Дождаться завершения всех потоков
for (auto& t : worker_threads) {
t.join();
}
std::cout << "Server shut down gracefully" << std::endl;
}
};
Server* Server::instance = nullptr;
int main() {
Server server;
server.run();
return 0;
}
9. Таблица основных сигналов
| Номер | Имя | По умолчанию | Описание |
|---|---|---|---|
| 1 | SIGHUP | Terminate | Hangup |
| 2 | SIGINT | Terminate | Interrupt (Ctrl+C) |
| 3 | SIGQUIT | Core dump | Quit |
| 9 | SIGKILL | Terminate | Kill (нельзя перехватить) |
| 15 | SIGTERM | Terminate | Termination signal |
| 18 | SIGCONT | Continue | Continue stopped process |
| 19 | SIGSTOP | Stop | Stop (нельзя перехватить) |
| 20 | SIGTSTP | Stop | Stop from tty (Ctrl+Z) |
| 10 | SIGUSR1 | Terminate | User-defined |
| 12 | SIGUSR2 | Terminate | User-defined |
Резюме
Послать сигнал из shell:
kill -SIGTERM <pid>
Послать сигнал из C++:
kill(pid, SIGTERM);
Обработать сигнал:
signal(SIGTERM, handler);
// или лучше:
sigaction(SIGTERM, &sa, nullptr);
Graceful shutdown: обработай SIGTERM, установи флаг, завершися чистенько.