Используйте sigaction()
, если у вас нет веских причин не делать этого.
Интерфейс signal()
имеет древность (и, следовательно, доступность) в его пользу, и он определен в стандарте C. Тем не менее, у него есть ряд нежелательных характеристик, которых sigaction()
избегает - если только вы не используете флаги, явно добавленные к sigaction()
, чтобы позволить ему точно имитировать старое поведение signal()
.
- Функция
signal()
(не обязательно) не блокирует поступление других сигналов во время выполнения текущего обработчика; sigaction()
может блокировать другие сигналы, пока не вернется текущий обработчик.
- Функция
signal()
(обычно) сбрасывает действие сигнала обратно на SIG_DFL
(по умолчанию) почти для всех сигналов. Это означает, что обработчик signal()
должен переустановить себя в качестве первого действия. Он также открывает окно уязвимости между моментом обнаружения сигнала и переустановкой обработчика, в течение которого, если поступает второй экземпляр сигнала, происходит поведение по умолчанию (обычно завершается, иногда с предубеждением - иначе дамп ядра).
- Точное поведение
signal()
варьируется в зависимости от системы - и стандарты допускают такие изменения.
Обычно это веские причины для использования sigaction()
вместо signal()
. Тем не менее, интерфейс sigaction()
, несомненно, более неудобный.
Какой бы из двух вариантов вы не использовали, не поддавайтесь искушению альтернативными интерфейсами сигналов, такими как
sighold()
,
sigignore()
,
sigpause()
и
sigrelse()
.
Номинально они являются альтернативой sigaction()
, но они только стандартизированы и присутствуют в POSIX для обратной совместимости, а не для серьезного использования. Обратите внимание, что стандарт POSIX говорит, что их поведение в многопоточных программах не определено.
Многопоточные программы и сигналы - это совсем другая сложная история. AFAIK, signal()
и sigaction()
в многопоточных приложениях в порядке.
Кукурузные стебли наблюдает :
Справочная страница Linux для signal()
говорит:
Эффекты signal()
в многопоточном процессе не определены.
Таким образом, я думаю, sigaction()
- единственное, что может безопасно использоваться в многопоточном процессе.
Это интересно. Страница руководства Linux в этом случае более строгая, чем POSIX. POSIX указывает для signal()
:
Если процесс многопоточный, или если процесс однопоточный и обработчик сигнала выполняется иначе, чем в результате:
- Процесс, вызывающий
abort()
, raise()
, kill()
, pthread_kill()
или sigqueue()
для генерации сигнала, который не блокируется
- Ожидающий сигнал разблокируется и доставляется до того, как вызов, который разблокировал, возвращает
поведение не определено, если обработчик сигнала ссылается на любой объект, кроме errno
со статической продолжительностью хранения, отличной от присвоения значения объекту, объявленному как volatile sig_atomic_t
, или если обработчик сигнала вызывает любую функцию, определенную в этом стандарт, отличный от одной из функций, перечисленных в Основные понятия сигнала .
Таким образом, POSIX четко определяет поведение signal()
в многопоточном приложении.
Тем не менее, sigaction()
следует предпочитать практически при любых обстоятельствах - и переносимый многопоточный код должен использовать sigaction()
, если нет веской причины, по которой он не может (например, «использовать только функции, определенные стандартом C»). - и да, код C11 может быть многопоточным). Именно это и говорит первый абзац этого ответа.