Примечание
Вызывать из обработчика сигнала все функции, например, printf, небезопасно. Удобный метод — использовать флаг, устанавливаемый в обработчике сигнала, и затем проверять этот флаг в функции mainи выводить сообщение, если нужно. В конце этой главы вы найдете список вызовов, которые можно безопасно применять в теле обработчиков сигналов.
Как это работает
Программа устроена так, что, когда вы задаете сигнал SIGINT, нажимая комбинацию клавиш +, вызывает функцию ouch. После того как функция прерывания ouchзавершится, программа продолжает выполняться, но восстанавливает реакцию на сигнал, принятую по умолчанию. (У разных версий UNIX, в особенности у потомков системы Berkeley UNIX, в течение многих лет сложилось разное поведение при получении сигналов. Если вы хотите восстановить поведение по умолчанию после возникновения сигнала, лучше всего запрограммировать его на конкретные действия.) Когда программа получает второй сигнал SIGINT, она выполняет стандартное действие, приводящее к завершению программы.
Если вы хотите сохранить обработчик сигнала и продолжать реагировать на комбинацию клавиш +, вам придется восстановить его, вызвав функцию signalеще раз. Это приведет к возникновению короткого промежутка времени, начиная с запуска функции прерывания и до момента восстановления обработчика сигнала, в течение которого сигнал не будет обрабатываться. Если второй сигнал будет получен в этот период, вопреки вашим желаниям программа может завершиться.
Примечание
Мы не рекомендуем вам пользоваться функцией signalдля перехвата сигналов. Мы включили ее в книгу, потому что она будет часто встречаться в более старых программах. Позже вы увидите sigaction, более четко определенный и надежный интерфейс, который следует применять в новых программах.
Функция signalвозвращает предыдущее значение обработчика для заданного типа сигнала, если таковой есть, или в противном случае SIG_ERRс установкой положительного значения в переменной errno. Если задан неверный сигнал или делается попытка обработать сигнал, который не может быть перехвачен или игнорироваться, например SIGKILL, переменной errnoприсваивается значение EINVAL.
Процесс может отправить сигнал другому процессу, включая себя самого, с помощью вызова функции kill. Вызов завершится аварийно, если у программы нет полномочий на отправку сигнала, часто потому что процесс-получатель принадлежит другому пользователю. Эта функция эквивалентна команде оболочки с тем же именем.
#include
#include
int kill(pid_t pid, int sig);
Функция killпосылает заданный сигнал sigпроцессу с идентификатором, заданным в аргументе pid. В случае успеха она возвращает 0. Для отправки сигнала посылающий процесс должен иметь право на выполнение этого действия. Обычно это означает, что у обоих процессов должен быть один и тот же идентификатор пользователя ID (т.е. вы можете отправить сигнал только одному из собственных процессов, хотя суперпользователь может отправлять сигналы любому процессу).
Функция killзавершится аварийно, вернет -1 и установит значение переменной errno, если задан неверный сигнал, ( errnoравна EINVAL), у процесса нет полномочий ( EPERM) или заданный процесс не существует ( ESRCH).
Сигналы предоставляют полезное средство, именуемое будильником или сигналом тревоги. Вызов функции alarmможет применяться для формирования сигнала SIGALRMв определенное время в будущем.
#include
unsigned int alarm(unsigned int seconds);
Вызов alarmнамечает доставку сигнала SIGALRMчерез secondsсекунд. В действительности сигнал будильника будет доставлен чуть позже из-за обработки задержек и учета неопределенностей. Значение 0 отменяет любой невыполненный запрос на сигнал будильника. Вызов функции alarmдо получения сигнала может вызвать сброс графика доставки. У каждого процесса может быть только один невыполненный сигнал будильника. Функция alarmвозвращает количество секунд, оставшихся до отправки любого невыполненного вызова, alarm, или -1 в случае аварийного завершения.
Читать дальше