1 60 => 170.955 [168.964...173.925] ~0.47915 (0.280279%)
2 34 => 76.9796 [76.8895...77.9694] ~0.0937379 (0.12177%)
В этом варианте (и диагностический вывод это подтверждает) мы искусственно ликвидировали наследование приоритета по цепочке порождения: сработавший таймер — функция потока — целевая функция объекта. Это не совсем соответствует цели, намеченной в начале этого раздела, но все же этот вариант иллюстрирует, что именно наш предыдущий вариант удовлетворял всем поставленным целям.
3. Сигналы
Сигналы инициируются некоторыми событиями в системе и посылаются процессу для его уведомления о том, что произошло нечто неординарное, требующее определенной реакции. Порождающее сигнал событие может быть действием пользователя или может быть вызвано другим процессом или ядром операционной системы. Сигналы являются одним из самых старых и традиционных механизмов UNIX. [27]
Уже из этого краткого описания можно заключить, что:
• действия, вызываемые для обработки сигнала, являются принципиально асинхронными;
• сигналы могут быть использованы как простейшее, но мощное средство межпроцессного взаимодействия.
Все сигналы определяются целочисленными константами, но для программиста это в принципе не так важно, поскольку каждому сигналу приписано символическое наименование вида
SIG*
<signal.h>
Посланный сигнал обрабатывается получившим его потоком или процессом (как уже обсуждалось ранее, собственно процесс ничего не может обрабатывать: это пассивная субстанция; понятно, что речь в таком контексте идет об обработке сигнала главным потоком процесса). Поток может отреагировать на полученный сигнал следующими способами (иногда действие, установленное для конкретного сигнала, называют диспозициейсигнала):
• Стандартное действие— выполнение действия, предписанного для обработки этого сигнала по умолчанию. Для многих сигналов действием по умолчанию является завершение, но это необязательно; есть сигналы, которые по умолчанию игнорируются. Для большей части сигналов, чьим действием по умолчанию является принудительное завершение процесса, предписано действие создания дампа памяти при завершении (core dump), но для некоторых, например
SYSINT
• Игнорирование сигнала— сигнал не оказывает никакого воздействия на ход выполнения потока получателя.
• Вызов обработчика— по поступлению сигнала вызывается функция реакции, определенная пользователем. Если для сигнала устанавливается функция-обработчик, то говорят, что сигнал перехватывается (относительно стандартного действия).
Для различных сигналов программа может установить различные механизмы обработки. Более того, в ходе выполнения программа может динамически переопределять реакции, установленные для того или иного сигнала.
Для большинства сигналов их воздействие можно перехватить из программного кода или игнорировать, но не для всех. Например, сигналы
SIGKILL
SIGSTOP
SIGSELECT
В QNX определены 64 сигнала в трех диапазонах:
• 1…40 — 40 POSIX-сигналов общего назначения;
• 41…56 — 16 POSIX-сигналов реального времени, введенных в стандарт позже (от
SIGRTMIN
SIGRTMAX);
• 57…64 — 8 сигналов, используемых в QNX Neutrino для специальных целей.
Начнем со специальных сигналов. Эти сигналы не могут быть проигнорированы или перехвачены: попытка вызвать
signal()
sigaction()
SignalAction()
EINVAL
sigprocmask()
SignalProcmask()
select()
#define SIGSELECT (SIGRTMAX + 1)
#define SIGPHOTON (SIGRTMAX + 2)
В силу своей недоступности эта группа сигналов представляет небольшой интерес для разработчика приложений.
Далее перейдем к POSIX-сигналам общего назначения (1…40), из которых назовем только самые употребляемые [28](пока мы описываем все сигналы в классической UNIX-нотации, не углубляясь в нюансы, например такие, как особенности реакции на них в многопоточном окружении):
•
SIGABRT (+) [6]
abort()
SIGABRT
•
SIGALRM [14]
setitimer()
ITIMER_REAL
•
SIGBUS (+) [10]
•
SIGCHLD [18]
#define SIGCLD SIGCHLD
•
SIGCONT [25]
SIGSTOP
•
SIGDEADLK [7]
27
Именно поэтому, наверное, стандарту POSIX так сложно органично согласовать их с нововведениями, например с парадигмой потоков.
28
Наличие круглых скобок после имени сигнала — признак того, что для этих сигналов реакция по умолчанию — принудительное завершение процесса; наличие (+) означает, что для этих сигналов предусмотрено создание дампа завершения, а наличие (-) — для этих сигналов дамп не создается. В квадратных скобках после имени сигнала указано численное значение, соответствующее данному сигналу, как оно определено в QNX.