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

В чём разница между прерываемыми и непрерываемыми сигналами в Linux?

1.7 Middle🔥 201 комментариев
#Linux и администрирование

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

🐱
deepseek-v3.2PrepBro AI5 апр. 2026 г.(ред.)

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

Разница между прерываемыми и непрерываемыми сигналами в Linux

В контексте системных вызовов и работы с сигналами в Linux, ключевое различие между прерываемыми (interruptible) и непрерываемыми (uninterruptible) состояниями/сигналами заключается в поведении системных вызовов при получении сигналов. Это фундаментальная концепция, влияющая на надёжность и отзывчивость процессов.

Основные определения

Прерываемые системные вызовы (например, с использованием флага SA_RESTART или по умолчанию для многих вызовов) могут быть прерваны сигналом. Если во время выполнения такого вызова процессу приходит сигнал, вызов завершается с ошибкой EINTR (Interrupted system call). Это позволяет процессу обработать сигнал немедленно, но требует от программиста корректной обработки прерываний.

#include <unistd.h>
#include <stdio.h>
#include <errno.h>

int main() {
    char buf[128];
    ssize_t n;
    
    // read() — пример прерываемого системного вызова
    n = read(STDIN_FILENO, buf, sizeof(buf));
    if (n == -1 && errno == EINTR) {
        printf("Системный вызов был прерван сигналом\n");
    }
    return 0;
}

Непрерываемые системные вызовы (часто связанные с операциями ввода-вывода или ожиданием аппаратных ресурсов) не могут быть прерваны сигналами. Процесс блокируется в состоянии D (Uninterruptible sleep), которое видно в выводе ps или top. Это состояние гарантирует, что критические операции (например, запись на диск или работа с драйверами) не будут прерваны, что предотвращает повреждение данных.

Ключевые отличия

  • Поведение при сигнале:

    • Прерываемые: Сигнал немедленно прерывает системный вызов, процесс получает управление для обработки сигнала.
    • Непрерываемые: Сигнал игнорируется до завершения системного вызова, процесс остаётся заблокированным.
  • Состояние процесса:

    • Прерываемые: Процесс в состоянии S (Interruptible sleep) в выводе ps.
    • Непрерываемые: Процесс в состоянии D (Uninterruptible sleep).
  • Типичные сценарии использования:

    • Прерываемые: Операции с сетевыми сокетами (read, write, accept), ожидание пользовательского ввода, таймауты.
    • Непрерываемые: Работа с блочными устройствами (дисками), некоторые операции файловой системы, взаимодействие с драйверами.

Примеры системных вызовов

  • Часто прерываемые: read, write, sleep, nanosleep, wait, accept.
  • Часто непрерываемые: Некоторые операции read/write к блочным устройствам, вызовы, связанные с виртуальной памятью в определённых условиях.

Практические последствия для разработки

Для прерываемых вызовов необходимо предусматривать повторные попытки (retry logic):

// Корректная обработка прерываемого вызова с повторной попыткой
ssize_t safe_read(int fd, void *buf, size_t count) {
    ssize_t n;
    do {
        n = read(fd, buf, count);
    } while (n == -1 && errno == EINTR);
    return n;
}

Для непрерываемых вызовов основная проблема — потенциальные "зависания", если оборудование или драйвер не отвечают. В таких случаях процесс может оставаться в состоянии D неопределённо долго, что иногда требует перезагрузки системы.

Настройка поведения через sigaction

Поведение можно частично контролировать через флаги sigaction:

struct sigaction sa;
sa.sa_handler = handler_func;
sa.sa_flags = SA_RESTART; // Автоматический перезапуск прерванных вызовов

sigaction(SIGINT, &sa, NULL);

Флаг SA_RESTART заставляет ядро автоматически перезапускать многие прерываемые системные вызовы после обработки сигнала, что упрощает программирование, но не работает для всех вызовов (например, не применяется к sleep или select).

Вывод

Понимание различий критично для создания отказоустойчивых и отзывчивых приложений. Прерываемые вызовы обеспечивают быструю реакцию на сигналы, но требуют аккуратной обработки ошибок. Непрерываемые вызовы обеспечивают целостность данных в критических операциях, но могут приводить к проблемам с отзывчивостью. В современных системах появляются гибридные подходы, например, системный вызов pselect, который атомарно изменяет маску сигналов и ожидает события, уменьшая окно возможных race conditions.

В чём разница между прерываемыми и непрерываемыми сигналами в Linux? | PrepBro