В чем разница между сигиграцией и сигналом? - PullRequest
123 голосов
/ 24 октября 2008

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

Ответы [ 8 ]

148 голосов
/ 24 октября 2008

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

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

  1. Функция signal() (не обязательно) не блокирует поступление других сигналов во время выполнения текущего обработчика; sigaction() может блокировать другие сигналы, пока не вернется текущий обработчик.
  2. Функция signal() (обычно) сбрасывает действие сигнала обратно на SIG_DFL (по умолчанию) почти для всех сигналов. Это означает, что обработчик signal() должен переустановить себя в качестве первого действия. Он также открывает окно уязвимости между моментом обнаружения сигнала и переустановкой обработчика, в течение которого, если поступает второй экземпляр сигнала, происходит поведение по умолчанию (обычно завершается, иногда с предубеждением - иначе дамп ядра).
  3. Точное поведение 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 может быть многопоточным). Именно это и говорит первый абзац этого ответа.

5 голосов
/ 24 октября 2008

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

Подробнее см. Примечание по безопасности .

4 голосов
/ 03 июля 2011

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

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

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

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

3 голосов
/ 23 мая 2014

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

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

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

2 голосов
/ 24 октября 2008

Из справочной страницы signal(3):

ОПИСАНИЕ

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

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

1 голос
/ 09 марта 2016

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

1 голос
/ 24 октября 2008

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

Цитирование из документации 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 или более поздняя версия, опубликованная Свободным программным обеспечением Фонд; без инвариантных разделов, без текстов на лицевой стороне, и без текстов на задней обложке. Копия лицензии включена в раздел «Лицензия на бесплатную документацию GNU».

0 голосов
/ 05 сентября 2018

со страницы руководства сигнал (7)

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

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

... и signal (2) , кажется, вызывает sigaction (2) в Linux с glibc.

...