Анимация
JavaScript


Главная  Библионтека 

0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 [ 193 ] 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242

use POSIX qw( signal h errno h),

$SIG{CHLD) = \&REAPER, sub REAPER { my Spid,

Spid = waitpid(-1, &WNOHANG),

If (Spid == -1) {

# Ожидающих потомков нет Игнорировать ) elsif (WIFEXITED($)) {

print Process Spid exited \n , } else {

print False alarm on $pid \n ,

SS1G{CHLD) = \&REAPER, # Ha случай ненадежных сигналов

Вторая ловушка, связанная с SIGCHLD, относится к Perl, а не к операционной системе. Поскольку system, open и запускают подпроцессы через fork, а операционная система отправляет процессу SIGCHLD при выходе из любого подпроцесса, вызов обработчика может быть и непредвиденным. Встроенные операции сами ожидают завершения потомков, поэтому иногда SIGCHLD прибывает до того, как вызов close для манипулятора заблокирует его для чистки. Если первым до него доберется обработчик сигнала, то к моменту нормального закрытия зомби уже не будет. В результате close вернет false и присвоит $значение No child processes . Если вызов close первым доберется до умершего потомка, waitpid возвращает 0.

В больщинстве систем поддерживается неблокирующий режим waitpid. Об этом можно узнать из стандартного модуля Perl Config.pm:

use Config,

$has nonblocking = $Config{d waitpid) eq define $Config{d wait4) eq define ,

Systeffl V определяет сигнал SIGCLD, который имеет тот же номер, что и SIGCHLD, но слегка отличается по семантике. Чтобы избежать путаницы, используйте SIGCHLD.

> Смотри также-

Раздел «Signals» рег/грс(1); описание функций wait и waitpid в peiifunc{\); документация по стандартному модулю POSIX; страницы руководства sigaction(2), signal(3) и ktll{2) вашей системы (если есть); рецепт 16.17.

16.20. Блокировка сигналов

Проблема

Требуется отложить прием сигнала - например, чтобы предотвратить непредсказуемые последствия от сигналов, которые могут прервать программу в любой момент.



Комментарий

в стандарт POSIX входят функции sigaction и sigprocmask, которые позволяют лучше управлять доставкой сигналов. Функция sigprocmask управляет отложенной доставкой сигналов, а sigaction устанавливает обработчики. При изменении %SIG Perl по возможности использует sigaction.

Чтобы использовать sigprocmask, сначала постройте набор сигналов методом POSIX SigSet->new. В качестве аргумента передается список номеров сигналов. Модуль POSIX экспортирует функции, возврашающие номера сигналов; имена функций совпадают с именами сигналов:

use POSIX qw( signal h),

Ssigset = POSIX SigSet->new( SIGINT, SIGKILL ),

Передайте объект POSIX::SigSet функции sigprocmask с нужным флагом. Флаг SIG BLOCK откладывает доставку сигнала. Флаг SIG UNBLOCK восстанавливает нормальную доставку сигналов, а SIG GETMASK блокирует только сигналы, содержащиеся в POSIX::SigSet. Самые отчаянные перестраховщики блокируют сигналы при вызове fork, чтобы предотвратить вызов обработчика сигнала в порожденном процессе перед тем, как Perl обновит его переменную $$ (идентификатор процесса). Если обработчик сигнала вызывается немедленно и сообщает значение $$, то вместо своего собственного $$ он может использовать родительское значение. Такая проблема возникает очень редко.

> Смотри также-

Страница руководства sigprocmask{2) вашей системы (если есть); документация но стандартному модулю POSIX.

Решение

Воспользуйтесь интерфейсом модуля POSIX к системной функции sigprocmask (только в POSIX-совместимых системах).

Блокировка сигнала на время выполнения операции выполняется так:

use POSIX qw( signal h),

$sigset = POSIX SigSet->new(SIGINT), # Определить блокируемые сигналы $old sigset = POSIX SigSet->new, # Для хранения старой маски

unless (defined sigprocmask(SIG BLOCK Ssigset, $old sigset)) { die Could not block SIGINT\n ,

Снятие блокировки выполняется так:

unless (defined sigprocmask(SIG UNBLOCK, $old sigset)) { die Could not unblock SIGINT\n ,



If ($@ =" /timeout/) {

# Тайм-аут, сделайте то, что считаете нужным

) else {

die, # Передать дальше неожиданное исключение

Комментарий

Функция alarm получает один аргумент: целое число секунд, после истечения которых ваш процесс получит SIGALRM. В сильно загруженных системах с разделением времени сигнал может быть доставлен позже указанного времени. По умолчанию SIGALRM завершает программу, поэтому вы должны установить собственный обработчик сигнала.

Функции alarm нельзя (с пользой) передать дробное число секунд; если вы попытаетесь это сделать, число секунд будет округлено до целого. Создание более точных таймеров рассматривается в рецепте 3.9.

[> Смотри также-

Раздел «Signals» perlipc(l); описание функции alarm в perlfunc(i); рецепт 3.9.

16.22. Программа: sigrand

Следующая программа выдает случайные иодниси с применением именованных каналов. Предполагается, что файл подписей хранится в формате программы fortune - то есть каждый многострочный блок завершается последовательностью %%\п . Приведем пример;

16.21. Тайм-аут

Проблема

Вы хотите гарантировать, что продолжительность некоторой операции не превышает заданный промежуток времени. Допустим, вы проводите архивацию файловой системы и хотите прервать ее, если она затянется более чем на час. Или вы хотите, чтобы через час произошло некоторое событие.

Решение

Чтобы прервать затянувшуюся операцию, используйте обработчик SIGALRM и вызовите в нем die. Установите таймер функцией alarm и включите код в aval:

$SIG{ALRM} = sub { die timeout ),

eval {

alarm(3600),

# Продолжительные операции alarm(O),

), If



0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 [ 193 ] 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242