Используйте, 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()
в порядке в многопоточных приложениях.
Cornstalks замечает :
На странице signal()
руководства Linux говорится:
Эффекты signal()
в многопоточном процессе не определены.
Таким образом, я думаю, sigaction()
это единственное, что можно безопасно использовать в многопоточном процессе.
Это интересно. В этом случае страница руководства Linux более строгая, чем POSIX. POSIX определяет signal()
:
Если процесс является многопоточным или если процесс является однопоточным и обработчик сигналов выполняется иначе, чем в результате:
- Процесс вызова
abort()
, raise()
, kill()
, pthread_kill()
, или , sigqueue()
чтобы генерировать сигнал , который не блокирован
- Ожидающий сигнал разблокируется и доставляется до вызова, который его разблокировал.
поведение не определено, если обработчик сигнала обращается к любому объекту, отличному от errno
статического продолжительности хранения, кроме присвоения значения объекту, объявленному как volatile sig_atomic_t
, или если обработчик сигнала вызывает любую функцию, определенную в этом стандарте, кроме одной из функций, перечисленных в Сигнальные концепции .
Итак, POSIX четко определяет поведение signal()
в многопоточном приложении.
Тем не менее, sigaction()
он должен быть предпочтительным практически во всех обстоятельствах - и переносимый многопоточный код следует использовать, sigaction()
если нет веской причины, по которой он не может (например, «использовать только функции, определенные стандартом C» - и да, код C11 может быть многопоточным -резьбовой). Об этом, по сути, и говорится в первом абзаце этого ответа.
signal
фактически описывает поведение Unix System V. POSIX допускает либо такое поведение, либо гораздо более разумное поведение BSD, но, поскольку вы не можете быть уверены, какой из них вы получите, лучше использовать егоsigaction
.