Оператор ожидания pause()
errno устанавливается в EINTR. Этот оператор дает нам еще один способ #include
#include
#include
int main(void) {
alarm(5);
cout << "Waiting to die in 5 seconds ..." << endl;
pause();
return EXIT_SUCCESS;
}
Описываемая модель обработки сигналов обладает рядом недостатков, считается устаревшей и, более того, как было показано, не обеспечивает надежную обработку сигналов. Тем не менее эту модель достаточно широко применяют в простых случаях, например при необходимости установить тайм-аут для некоторой операции. Вот как, к примеру, устанавливается тайм-аут ожидания установления соединения в TCP/IP-клиенте [9]:
void alarm_handler(int sig) { return; }
int main() {
...
signal(SIGALRM, alarm_handler); alarm(5);
int rc = connect( ... );
alarm(0);
if (rc < 0 && errno == EINTR)
cout << "Истек тайм-аут" << endl, exit(EXIT_FAILURE);
...
}
Здесь уместно напомнить немаловажное обстоятельство, связанное с сигналами, которое обделяется вниманием во многих руководствах по программированию: большинство блокирующих вызовов API (connect()
delay(), wait(), waitid() и многие другие) будут разблокированы при получении блокированным потоком любого сигнала. Такие вызовы API, как pause() и sigwait(), вообще предназначены только для выполнения пассивной блокировки до момента поступления сигнала. Многие их них возвращают значение или устанавливают в качестве кода системной ошибки errno значение EINTR, специально отведенное для отражения такого результата завершения, как прерывание поступившим извне сигналом. Мы неоднократно будем использовать это обстоятельство в тексте примеров программного кода, например:if (delay(100) != 0)
В данном случае учитываем, что функция delay()
Модель надежных сигналов
В более поздней («новой») модели обработки сигналов (называемой еще моделью надежных сигналов) используются не единичные сигналы, а наборы сигналов — тип sigset_t
POSIX требует, чтобы в реализации тип sigset_t
sigset_t в QNX, как и большинство фундаментальных для системы определений, находится в заголовочном файле :struct { long bits[2]; }
Понятно, что в этом случае тип sigset_t
Для формирования сигнальных наборов определяется набор специальных операций:
• sigemptyset(sigset_t *set)
set, исключая из него все сигналы;• sigfillset(sigset_t *set)
set, включая в него все сигналы;• sigaddset(sigset_t *set, int signo)
set единичный сигнал signo;• sigdelset(sigset_t *set, int signo)
set единичный сигнал signo.В качестве signo
SIGINT), либо численное значение сигнала, но в этом случае код становится зависимым от системы. Легко увидеть, что, пользуясь совокупностью этих 4-х операций, можно сформировать любой произвольный набор сигналов. Например:sigset_t sig;
sigemptyset(&sig);
sigaddset(&sig, SIGPOLL);