← Назад к вопросам

Можно ли заблокировать сигналы?

2.3 Middle🔥 141 комментариев
#Linux и операционные системы#Многопоточность и синхронизация

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI29 мар. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Блокировка сигналов в Unix/Linux

Да, в Unix/Linux можно и нужно блокировать сигналы (signal masking). Это один из самых важных механизмов для управления обработкой сигналов в многопоточных и критичных приложениях.

Концепция маски сигналов

Маска сигналов (signal mask) — это набор сигналов, доставка которых временно приостановлена. Заблокированный сигнал не игнорируется, а ставится в очередь и доставляется, когда будет разблокирован.

Блокировка сигналов через sigprocmask() (POSIX)

Основной механизм для однопоточных приложений:

#include <signal.h>
#include <unistd.h>

sigset_t set, oldset;

// Инициализируем пустой набор
sigemptyset(&set);

// Добавляем SIGTERM в набор
sigaddset(&set, SIGTERM);
sigaddset(&set, SIGINT);

// Блокируем эти сигналы
sigprocmask(SIG_BLOCK, &set, &oldset);  // SIG_BLOCK — добавляет к маске

// Критическая секция, где сигналы не будут обработаны
// ...

// Восстанавливаем исходную маску
sigprocmask(SIG_SETMASK, &oldset, nullptr);

Операции с маской

  • SIG_BLOCK — добавить сигналы в маску (блокировать)
  • SIG_UNBLOCK — удалить сигналы из маски (разблокировать)
  • SIG_SETMASK — установить маску (заменить полностью)

Для многопоточных приложений: pthread_sigmask()

Для потокобезопасности используй pthread_sigmask():

#include <signal.h>
#include <pthread.h>

sigset_t set;
sigemptyset(&set);
sigaddset(&set, SIGTERM);
sigaddset(&set, SIGUSR1);

// Блокируем сигналы в этом потоке
pthread_sigmask(SIG_BLOCK, &set, nullptr);

// Сигналы будут доставлены другому потоку (если он их не заблокировал)

Критическое различие: sigprocmask() работает с процессом, pthread_sigmask() — с отдельным потоком.

Обработка заблокированных сигналов через sigwait()

Синхронная обработка вместо асинхронных обработчиков:

#include <signal.h>
#include <iostream>

void* signal_handler_thread(void* arg) {
    sigset_t* set = (sigset_t*)arg;
    int sig;
    
    while (true) {
        // Ждем сигнала синхронно
        if (sigwait(set, &sig) == 0) {
            std::cout << "Получен сигнал: " << sig << std::endl;
            
            if (sig == SIGTERM) {
                std::cout << "Завершение приложения" << std::endl;
                break;
            }
        }
    }
    return nullptr;
}

int main() {
    sigset_t set;
    pthread_t thread;
    
    sigemptyset(&set);
    sigaddset(&set, SIGTERM);
    sigaddset(&set, SIGINT);
    
    // Блокируем сигналы во всех потоках
    pthread_sigmask(SIG_BLOCK, &set, nullptr);
    
    // Создаем поток для обработки сигналов
    pthread_create(&thread, nullptr, signal_handler_thread, &set);
    
    // Основная работа
    while (true) {
        sleep(1);
    }
    
    pthread_join(thread, nullptr);
    return 0;
}

Сигналы, которые нельзя блокировать

SIGKILL и SIGSTOP никогда не могут быть заблокированы — это гарантирует, что ОС может принудительно остановить процесс.

Практические примеры

Защита критических операций:

void critical_operation() {
    sigset_t set, oldset;
    sigemptyset(&set);
    sigaddset(&set, SIGALRM);
    sigaddset(&set, SIGTERM);
    
    // Блокируем сигналы
    pthread_sigmask(SIG_BLOCK, &set, &oldset);
    
    // Выполняем атомарную операцию
    // Сигналы не прерывают выполнение
    
    // Восстанавливаем маску
    pthread_sigmask(SIG_SETMASK, &oldset, nullptr);
}

Когда использовать блокировку сигналов

  1. Критические секции — операции с базой данных, транзакции
  2. Многопоточность — предотвращение race conditions
  3. Безопасная очистка ресурсов — перед выходом из программы
  4. Синхронная обработка — вместо сложных обработчиков сигналов
  5. Инициализация — блокируем сигналы при запуске, разблокируем после

Возвращение к исходной маске

Всегда сохраняй старую маску и восстанавливай её:

sigset_t set, oldset;
sigemptyset(&set);
sigaddset(&set, SIGTERM);
pthread_sigmask(SIG_BLOCK, &set, &oldset);  // Сохраняем в oldset

// ... работа ...

pthread_sigmask(SIG_SETMASK, &oldset, nullptr);  // Восстанавливаем

Блокировка сигналов — это фундаментальный инструмент для создания надежных и безопасных системных приложений.