Я собирался добавить дополнительный обработчик сигнала в приложение, которое у нас есть, и заметил, что автор использовал sigaction для настройки других обработчиков сигналов. Я собирался использовать сигнал. Чтобы следовать конвенции, я должен использовать sigaction, но если бы я писал с нуля, что выбрать?
В чем разница между сигмацией и сигналом?
Ответ 1
Используйте sigaction()
, если у вас нет очень веских причин не делать этого.
Интерфейс signal()
имеет античность (и, следовательно, доступность) в свою пользу и определен в стандарте C. Тем не менее, он имеет ряд нежелательных характеристик, которые sigaction()
избегает - если вы не используете флаги, явно добавленные в sigaction()
, чтобы позволить ему точно моделировать старое поведение signal()
.
- Функция
signal()
не (обязательно) блокирует другие сигналы от прибытия, пока выполняется текущий обработчик;sigaction()
может блокировать другие сигналы до тех пор, пока текущий обработчик не вернется. - Функция
signal()
(обычно) сбрасывает действие сигнала обратно наSIG_DFL
(по умолчанию) для почти всех сигналов. Это означает, что обработчикsignal()
должен переустановить себя как свое первое действие. Он также открывает окно уязвимости между временем обнаружения сигнала и переустановкой обработчика, в течение которого, если приходит второй экземпляр сигнала, происходит поведение по умолчанию (обычно заканчивается, иногда с предубеждением - aak core dump). - Точное поведение
signal()
варьируется между системами - и стандарты допускают эти изменения.
Это, как правило, веские причины для использования sigaction()
вместо signal()
. Тем не менее, интерфейс sigaction()
, несомненно, более неудобным.
Какой бы из двух вы ни использовали, не соблазняйтесь альтернативными сигнальными интерфейсами, такими как
sighold()
,
sigignore()
,
sigpause()
и
sigrelse()
.
Они номинально альтернативны sigaction()
, но они едва стандартизированы и присутствуют в POSIX для обратной совместимости, а не для серьезного использования. Обратите внимание, что стандарт POSIX говорит, что их поведение в многопоточных программах - undefined.
Многопоточные программы и сигналы - это еще одна сложная история. AFAIK, как signal()
, так и sigaction()
в порядке многопоточных приложений.
Страница руководства Linux для
signal()
говорит:
Эффекты
signal()
в многопоточном процессе не определены.Таким образом, я думаю, что
sigaction()
является единственным, который можно безопасно использовать в многопоточном процессе.
Это интересно. В этом случае страница руководства Linux более ограничительна, чем POSIX. POSIX указывает на signal()
:
Если процесс многопоточен или процесс однопоточен, а обработчик сигнала выполняется иначе, чем в результате:
- Процесс, вызывающий
abort()
,raise()
,kill()
,pthread_kill()
илиsigqueue()
для генерации сигнала, который не заблокирован- Отложенный сигнал, который разблокирован и доставляется до разблокированного вызова, возвращает
поведение undefined, если обработчик сигнала ссылается на любой объект, отличный от
errno
со статической продолжительностью хранения, отличной от назначения значения объекту, объявленному какvolatile sig_atomic_t
, или если обработчик сигнала вызывает любую функцию, определенную в этом стандарте, отличном от одной из функций, перечисленных в Концепции сигналов.
Итак, POSIX четко определяет поведение signal()
в многопоточном приложении.
Тем не менее, sigaction()
предпочтительнее, по существу, во всех случаях - и переносимый многопоточный код должен использовать sigaction()
, если не будет подавляющей причины, почему он не может (например, использовать только функции, определенные стандартом C) - и да, код C11 может быть многопоточным). Это, в основном, то, что говорит и первый абзац этого ответа.
Ответ 2
Это разные интерфейсы для сигнальных устройств ОС. Нужно предпочесть использовать sigaction для сигнала, если это возможно, поскольку сигнал() имеет определенную реализацию (часто расходящуюся) и ведет себя по-разному в Windows, OS X, Linux и других системах UNIX.
Подробнее см. примечание по безопасности.
Ответ 3
Для меня этой ниже строки было достаточно, чтобы решить:
Функция sigaction() предоставляет более всеобъемлющий и надежный механизм управления сигналами; новый приложения должны использовать sigaction() а не сигнал()
http://pubs.opengroup.org/onlinepubs/009695399/functions/signal.html#tag_03_690_07
Если вы начинаете с нуля или изменяете старую программу, sigaction должен быть правильным вариантом.
Ответ 4
Я бы использовал signal(), поскольку он более портативен, теоретически, по крайней мере. Я проголосую за любого комментатора, который может придумать современную систему, которая не имеет уровня совместимости POSIX и поддерживает сигнал().
Цитата из Документация GLIBC:
Можно использовать как функцию сигнала, так и сиг- одна программа, но вы должны быть осторожны, потому что они могут взаимодействуют немного странными способами.
Функция sigaction указывает больше информации, чем сигнал функция, поэтому возвращаемое значение из сигнала не может выразить полное диапазон возможностей сигментации. Поэтому, если вы используете сигнал для сохранить и позже восстановить действие, возможно, он не сможет правильно восстановите обработчик, который был установлен с помощью sigaction.
Чтобы избежать проблем в результате, всегда используйте sigaction для сохранения и восстановить обработчик, если ваша программа вообще использует sigaction. поскольку sigaction является более общим, он может правильно сохранять и восстанавливать любые независимо от того, было ли оно первоначально создано с сигнал или сигма.
В некоторых системах, если вы устанавливаете действие с сигналом, а затем проверьте его с помощью sigaction, адрес обработчика, который вы получаете, может не будь то то, что вы указали с сигналом. Возможно, это даже не подходящий для использования в качестве аргумента действия с сигналом. Но вы можете положиться об использовании его в качестве аргумента для sigaction. Эта проблема никогда не бывает в системе GNU.
Итак, вам лучше использовать тот или иной механизм последовательно в рамках одной программы.
Примечание по переносимости: основная сигнальная функция - это функция ISO C, в то время как sigaction является частью стандарта POSIX.1. Если ты заинтересованы в переносимости для не-POSIX-систем, тогда вы должны вместо этого используйте сигнальную функцию.
Copyright (C) 1996-2008 Free Software Foundation, Inc.
Разрешается копировать, распространять и/или изменять это документ в соответствии с условиями лицензии GNU Free Documentation License, Версия 1.2 или любая более поздняя версия, опубликованная Free Software Фонд; без инвариантных разделов, без текстов с передней обложкой, и без текстур задней обложки. Копия лицензии включена в раздел "Лицензия на бесплатную документацию GNU".
Ответ 5
На странице signal(3)
:
ОПИСАНИЕ
This signal() facility is a simplified interface to the more general sigaction(2) facility.
Оба ссылаются на один и тот же базовый объект. Вы должны, по-видимому, не манипулировать откликом один сигнал с обоими, но их смешивание не должно вызывать что-либо...
Ответ 6
signal() является стандартным C, sigaction() не является.
Если вы можете использовать либо (то есть, вы находитесь в системе POSIX), а затем используйте sigaction(); он не определен, будет ли сигнал() сбрасывать обработчик, а это значит, что для переносимости вы должны снова вызвать сигнал() внутри обработчика. Что хуже того, что есть гонка: если вы получаете два сигнала в быстрой последовательности, а вторая доставляется до переустановки обработчика, вы будете иметь действие по умолчанию, которое, вероятно, будет убивать ваш процесс. sigaction(), с другой стороны, гарантируется использование "надежной" семантики сигнала. Вам не нужно переустанавливать обработчик, потому что он никогда не будет reset. С помощью SA_RESTART вы также можете получить системные вызовы для автоматического перезапуска (поэтому вам не нужно вручную проверять EINTR). sigaction() имеет больше опций и является надежным, поэтому рекомендуется его использование.
Psst... не рассказывайте никому, я сказал вам это, но POSIX в настоящее время имеет функцию bsd_signal(), которая действует как signal(), но дает семантику BSD, что означает ее надежность. Его основное назначение - переносить старые приложения, которые предполагают надежные сигналы, и POSIX не рекомендует использовать его.
Ответ 7
Я бы также предложил использовать sigaction() над сигналом() и хотел бы добавить еще одну точку. sigaction() дает вам больше возможностей, таких как pid процесса, который умер (возможно, используя структуру siginfo_t).