QNX/UNIX: Анатомия параллелизма - Цилюрик Олег Иванович
}Описываемая модель обработки сигналов обладает рядом недостатков, считается устаревшей и, более того, как было показано, не обеспечивает надежную обработку сигналов. Тем не менее эту модель достаточно широко применяют в простых случаях, например при необходимости установить тайм-аут для некоторой операции. Вот как, к примеру, устанавливается тайм-аут ожидания установления соединения в 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()pause()sigwait()errnoEINTR
if (delay(100) != 0)В данном случае учитываем, что функция
delay()Модель надежных сигналов
В более поздней («новой») модели обработки сигналов (называемой еще моделью надежных сигналов) используются не единичные сигналы, а наборы сигналов — тип
sigset_tPOSIX требует, чтобы в реализации тип
sigset_tsigset_t<target_nto.h>
struct { long bits[2]; }Понятно, что в этом случае тип
sigset_tДля формирования сигнальных наборов определяется набор специальных операций:
•
sigemptyset(sigset_t *set)set•
sigfillset(sigset_t *set)set•
sigaddset(sigset_t *set, int signo)setsigno•
sigdelset(sigset_t *set, int signo)setsignoВ качестве
signoSIGINT
sigset_t sig;
sigemptyset(&sig);
sigaddset(&sig, SIGPOLL);
sigaddset(&sig, SIGALRM);Этот фрагмент кода формирует сигнальный набор, состоящий из двух сигналов:
SIGPOLLSIGALRMДиспозиция обработки каждого сигнала в этой модели устанавливается функцией:
int sigaction(int signo, const struct sigaction *act, struct sigaction *oact);где
signo
act
oactNULLСтруктура описания обработчика
sigaction
struct sigaction {
#define sa_handler un._sa_handler
#define sa_sigaction un._sa_sigaction
union {
void (*_sa_handler)(_SIG_ARGS);
void (*_sa_sigaction)(int, siginfo_t*, void*);
} un;
int sa_flags;
sigset_t sa_mask;
};Это определение по форме, но не по содержанию отличается от описания, показанного в POSIX и используемого во многих традиционных UNIX [5] (обратите внимание на изменение порядка следования полей маски и флагов; это может стать преградой для прямой инициализации структуры в стиле C++ из соображений переносимости):
struct sigaction {
/* указатель на функцию обработчика сигнала */
void (*sa_handler)(int);
/* сигналы, блокирующиеся во время обработки */
sigset_t sa_mask;
/* флаги, влияющие на поведение сигнала */
int sa_flags;
/* указатель на функцию обработчика сигнала */
void (*sa_sigaction)(int, siginfo_t*, void*);
};Определения
#defineunion