Нужно тщательно программировать сигналы, потому что существует ряд "состояний гонок", возникающих в программах, применяющих сигналы. Например, если вы намерены вызвать pause для ожидания сигнала и этот сигнал возникнет до вызова pause, ваша программа может ждать неопределенно долго события, которое не произойдет. Новоиспеченный программист сталкивается с множеством таких состояний гонок, важных проблем синхронизации или согласования времени. Всегда очень внимательно проверяйте программный код, использующий сигналы.
Мы рассмотрели подробно возбуждение и перехват сигналов с помощью signal
sigaction, который более надежен.#include
int sigaction
Структура sigaction
sig, определена в файле signal.h и как минимум включает следующие элементы:void (*)(int)sa_handler /* функция, SIG_DFL или SIG_IGN */
sigset_t sa_mask /* сигналы, заблокированные для sa_handler */
int sa_flags /* модификаторы действий сигнала */
Функция sigaction
sig. Если oact не null, sigaction записывает предыдущее действие для сигнала в указанное oact место. Если act равен null, это все, что делает функция sigaction. Если указатель act не null, задается действие для указанного сигнала.Как и функция signal
sigaction возвращает 0 в случае успешного выполнения и -1 в случае ошибки. Переменная errno получит значение EINVAL, если заданный сигнал некорректен или была предпринята попытка захватить или проигнорировать сигнал, который нельзя захватывать или игнорировать.В структуре sigaction
act, sa_handler — это указатель на функцию, вызываемую при получении сигнала sig. Она очень похожа на функцию func, которая, как вы видели раньше, передавалась функции signal. Вы можете применять специальные значения SIG_IGN и SIG_DFL в поле sa_handler для обозначения того, что сигнал должен игнорироваться или должно быть восстановлено действие по умолчанию, соответственно.Поле sa_mask
sa_handler. Это множество сигналов, которые блокируются и не должны доставляться процессу. Такое поведение мешает возникновению ситуации, описанной ранее, в которой сигнал был получен до того, как его обработчик дошел до завершения. Применение поля sa_mask может устранить это состояние гонок.Однако сигналы, захватываемые обработчиками, заданными в структуре sigaction
sa_flags значение SA_RESETHAND, если хотите добиться поведения, виденного вами раньше при обсуждении функции signal. Прежде чем обсуждать подробнее sigaction, давайте перепишем программу ctrlc.c, применяя sigaction вместо функции signal (упражнение 11.9).sigactionВнесите приведенные далее изменения, так чтобы сигнал SIGINT
sigaction. Назовите новую программу ctrlc2.c.#include
#include
#include
void ouch(int sig) {
printf("OUCH! - I got signal %d\n", sig);
}
int main {
struct sigaction act;
while (1) {
printf("Hello World!\n");
sleep(1);
}
}
Когда вы выполните эту версию программы, то всегда будете получать сообщение при нажатии комбинации клавиш SIGINT
sigaction. Для завершения программы следует нажать комбинацию клавиш SIIGQUIT$ ./ctrlc2
Hello World!
Hello World!
Hello World!
^C
OUCH! - I got signal 2
Hello World!
Hello World!
^C
OUCH! - I got signal 2
Hello World!
Hello World!
^\
Quit
$
Как это работает