В чем разница между информацией и сигналом?

Я собирался добавить дополнительный обработчик сигналов в приложение, которое у нас есть, и я заметил, что автор использовал sigaction для настройки других обработчиков сигналов. Я собирался использовать сигнал. Чтобы следовать соглашению, я должен использовать sigaction, но если бы я писал с нуля, что я должен выбрать?

8 ответов


использовать sigaction() если у вас нет очень веских причин не делать этого.

на signal() интерфейс имеет древность (и, следовательно, доступность) в свою пользу, и он определен в стандарте C. Тем не менее, он имеет ряд нежелательных характеристик, которые sigaction() избегает-если вы не используете флаги, явно добавленные в sigaction() чтобы позволить ему точно имитировать старый signal() поведение.

  1. на signal() функция не (обязательно) блокирует поступление других сигналов во время выполнения текущего обработчика; sigaction() может блокировать другие сигналы, пока текущий обработчик возвращает.
  2. на signal() функция (обычно) сбрасывает действие сигнала обратно в SIG_DFL (по умолчанию) почти все сигналы. Это означает, что signal() обработчик должен переустановить себя в качестве первого действия. Он также открывает окно уязвимости между временем обнаружения сигнала и обработчиком переустановка, во время которой, если поступает второй экземпляр сигнала, происходит поведение по умолчанию (обычно завершается, иногда с предубеждением - aka core dump).
  3. точное поведение signal() меняет между системами - и стандарты позволяют эти изменения.

они, как правило, веские причины для использования sigaction() вместо signal(). Однако интерфейс sigaction() - Это, несомненно, сложнее.

какой из двух вы используете, не соблазнитесь альтернативными интерфейсами сигнала, такими как sighold(), sigignore(), sigpause() и sigrelse(). Номинально они являются альтернативами sigaction(), но они только едва стандартизированы и присутствуют в POSIX для обратной совместимости, а не для серьезного использования. Обратите внимание, что стандарт POSIX говорит, что их поведение в многопоточных программах не определено.

многопоточные программы и сигналы-это целое другая сложная история. насколько я знаю, как signal() и sigaction() в порядке в многопоточных приложениях.

мелкий отмечает:

man-страница 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 может быть многопоточным). Это в основном то, что открывающий абзац этого ответа также говорит.


Это разные интерфейсы для сигнальных устройств ОС. Следует предпочесть использовать sigaction для сигнала, если это возможно, поскольку signal () имеет определенное реализацией (часто склонное к гонке) поведение и ведет себя по-разному в Windows, OS X, Linux и других системах UNIX.

посмотреть этот безопасность для сведения.


для меня этой нижней строки было достаточно, чтобы решить:

функция sigaction() предоставляет более всесторонний и надежный механизм управления сигналами; новый приложения должны использовать sigaction() вместо signal ()

http://pubs.opengroup.org/onlinepubs/009695399/functions/signal.html#tag_03_690_07

Если вы начинаете с нуля или модифицируете старую программу, sigaction должен быть правильным выбор.


С signal(3) man page:

описание

 This signal() facility is a simplified interface to the more
 general sigaction(2) facility.

использовать один и тот же базовый объект. Вы должны предположительно не манипулировать ответом на один сигнал с обоими, но смешивание их не должно вызывать ничего сломать...


Я бы использовал signal (), так как он более портативный, по крайней мере теоретически. Я проголосую за любого комментатора, который может придумать современную систему, которая не имеет уровня совместимости POSIX и поддерживает signal().

слово документация GLIBC:

возможно использовать и функции сигнала и sigaction внутри одной программы, но вы должны быть осторожны, потому что они могут взаимодействуйте немного странным образом.

функция sigaction указывает больше информации, чем сигнал функция, поэтому возвращаемое значение от сигнала не может выразить полное диапазон возможностей sigaction. Поэтому, если вы используете сигнал сохранить и позже восстановить действие, возможно, не удастся восстановите правильно обработчик, который был установлен с помощью sigaction.

чтобы избежать проблем в результате, всегда используйте sigaction для сохранения и восстановите обработчик, если ваша программа использует sigaction вообще. С sigaction более общий, он может правильно сохранить и восстановить любые действие, независимо от того, было ли оно первоначально установлено с сигнал или вызов sigaction.

в некоторых системах, если вы устанавливаете действие с сигналом, а затем проверьте его с помощью sigaction, адрес обработчика, который вы получаете, может не быть таким же, как указано с помощью сигнала. Может быть, и нет. подходит для использования в качестве аргумента действия с сигналом. Но вы можете положиться использовать его в качестве аргумента в sigaction. Эта проблема никогда не возникает о системе GNU.

Итак, вам лучше использовать один или другой из механизмов последовательно в рамках одной программы.

Примечание Удобоносимости: основная функция сигнала особенность ИСО к, в то время как sigaction является частью POSIX.Стандарт 1. Если ты ... обеспокоенный переносимостью в системы non-POSIX, вы должны вместо этого используйте функцию сигнала.

Авторское Право (C) 1996-2008 Бесплатно Software Foundation, Inc.

разрешается копировать, распространять и/или изменять этот документ на условиях лицензии GNU Free Documentation, Версии 1.2 или любой более поздней версией, опубликованной Free программное обеспечение Фундамент; без инвариантных разделов, без текстов на обложке, и без переписки. Копия лицензии включена в раздел под названием "GNU Free Documentation License".


signal() является стандартным C, sigaction () - нет.

Если вы можете использовать либо (то есть, вы находитесь в системе POSIX), то используйте sigaction(); не указано, сбрасывает ли signal() обработчик, что означает, что для переносимости вы должны снова вызвать signal() внутри обработчика. Хуже всего то, что есть гонка: если вы получите два сигнала в быстрой последовательности, а второй будет доставлен до переустановки обработчика, у вас будет действие по умолчанию, которое, вероятно, будет чтобы убить процесс. sigaction (), С другой стороны, гарантируется использование "надежных" семантика сигнала. Вам не нужно переустановить обработчик, потому что он никогда не будет сброшен. С помощью SA_RESTART вы также можете получить некоторые системные вызовы для автоматического перезапуска (поэтому вам не нужно вручную проверять EINTR). sigaction () имеет больше вариантов и надежно, поэтому своя польза ободрена.

Psst... не говорите никому, что я сказал вам это, но POSIX в настоящее время имеет функцию bsd_signal (), который действует как signal (), но дает семантику BSD, что означает, что он надежен. Его основное использование-перенос старых приложений, которые предполагали надежные сигналы, и POSIX не рекомендует его использовать.


Я бы также предложил использовать sigaction () над signal () и хотел бы добавить еще одну точку. sigaction () дает вам больше опций, таких как pid процесса, который умер (возможно, используя структуру siginfo_t).


из man page сигнал(7)

процесс-направленный сигнал может быть доставлен в любой один из потоков, который в настоящее время не имеет заблокированного сигнала. Если более чем один из потоков имеет сигнал разблокирован, то ядро выбирает произвольный поток, на который будет подаваться сигнал.

и я бы сказал, что эта "проблема" существует для Сигнал(2) и sigaction (2). Так что будьте осторожны с сигналами и компиляции.

... и Сигнал(2) Кажется, назвал sigaction (2) внизу в Linux с glibc.