Анимация
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

сигнал SIGINT, но за ее пределами SIGINT должен обрабатываться обычными средствами.

Решение

Используйте local для временного переопределения обработчика:

# Обработчик сигнала sub ding {

$SIG{INT) = \&ding;

warn "XaEnter your name\n";

# Запросить имя с переопределением SIGINT sub get name {

local $S1G{INT) = \&ding; my Sname;

print "Kindly Stranger, please enter your name "; chomp( Sname = <> ); return Sname:

Комментарий

Для временного сохранения одного элемента %SIG необходимо использовать local, а не гпу. Изменения продолжают действовать во время выполнения блока, включая все, что может быть вызвано из него. В приведенном примере это подпрограмма get name. Если сигнал будет доставлен во время работы другой функции, вызванной вашей функцией, сработает ваш обработчик сигнала - если только вызванная подпрограмма не установила собственный обработчик. Предыдущее значение элемента хэша автоматически восстанавливается при выходе из блока. Это один из немногочисленных случаев, когда динамическая область действия оказывается скорее удобной, нежели запутанной.

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

Рецепты 10.13; 16.15; 16.18.

16.17. Написание обработчика сигнала

Проблема

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

Решение

Обработчик сигнала представляет собой обычную подпрограмму. С некоторой степенью риска в обработчике можно делать все, что допустимо в любой другой подпрограмме Perl, но чем больше вы делаете, тем больше рискуете.



16.17. Написание обработчика сигнала 591

В некоторых системах обработчик должен переустанавливаться после каждого сигнала:

$SIG{INT) = \&got int; sub got int {

$SIG{INT) = \&got int; # Ho не для SIGCHLD!

# . . .

Некоторые системы перезапускают блокирующие операции (например, чтение данных). В таких случаях необходимо вызвать в обработчике die и перехватить вызов aval:

my Smterrupted = 0;

sub got int {

Smterrupted = 1;

$SIG{INT} = DEFAULT-; # или IGNORE

die;

eval {

$SIG{INT) = \&got int;

# .. Длинный код, который нежелательно перезапускать

if (Smterrupted) {

# Разобраться с сигналом

Комментарий

Установка собственного обработчика сигнала напоминает игру с огнем: это очень интересно, но без исключительной осторожности вы рано или поздно обожжетесь. Создание кода Perl, предназначенного для обработки сигналов, чревато двумя опасностями. Во-первых, многие библиотечные функции нереентерабельны. Если сигнал прерывает выполнение какой-то функции (например, malloc(3) или printf(3)), а ващ обработчик сигнала снова вызовет ее, результат окажется непредсказуемым - обычно работа программы прерывается с выводом в файл содержимого памяти (core dump). Во-вторых, на нижних уровнях нереентерабелен сам Perl (версия 5.005 будет поддерживать облегченные процессы, называемые нитями (threads), но на момент издания этой книги она еще не вышла). Если сигнал прерывает Perl в момент изменения его собственных внутренних структур данных, результат тоже непредсказуем - как правило, выдаются случайные дампы.

Перед вами открываются два пути: параноидальный и практический. Параноик постарается ничего не делать внутри обработчика сигнала; примером служит код с aval и dia в решении - мы присваиваем значение переменной и тут же выходим из обработчика. Но даже это покажется слишком рискованным настоящему параноику, который избегает dla в обработчиках - вдруг система на что-нибудь обидится? Практический подход - вы говорите: «Кто не рискует, тот не выигрывает», - и делаете в обработчике все, что заблагорассудится.



Сигналы были реализованы во многих операционных системах, причем не всегда одинаково. Отличия в реализации сигналов чаще всего проявляются в двух ситуациях: когда сигнал происходит во время активности обработчика {надежность) и когда сигнал прерывает блокирующий вызов системной функции типа read или accept {перезапуск).

Первоначальная реализация сигналов была ненадежной. Это означало, что во время работы обработчика при других ностуилениях сигнала происходило некоторое стандартное действие (обыч1Ю авари11Ное завершение программы). Новые системы решают эту проблему (конечно, каждая - в своем, слегка особом стиле), позволяя подавлять другие экземпляры сигналов с данным номером до завершения обработчика. Если Perl обнаружит, что ваша система может использовать надежные сигналы, он генерирует соответствующие вызовы системных функций, чтобы программы вели себя более логично и безопасно. Система сигналов P0S1X позволяет запретить доставку сигналов и в другие моменты времени (см. рецепт 16.20).

Чтобы получить по-настоящему нереносимыг! код, программист-паранонк заранее предполагает самое худшее (ненадежные сигналы) и вручную переустанавливает обработчик сигналов, обычно в самом начале функции:

$SIG{INT} = \&catcher sub catcher { t)

$SIG{INT} = \&catcher,

Особый случай перехвата SIGCHLD описан в рецепте 16.19. Systera V ведет себя очень странно и может сбить с толку.

Чтобы узнать, располагаете ли вы надежными сигналами, воспользуйтесь модулем Config:

use Config,

print Hurrah\n if $Config{d sigaction}

Наличие надежных сигналов еще не означает, что вы автоматически получаете надежную программу. Впрочем, без них программа заведомо окажется ненадежной.

Первые реализации сигналов прерывали медленные вызовы системных функций, которые требовали взаимодействия со стороны других процессов или драйверов устройств. Если сигнал ностунает во время выполнения этих функций, они (и их аналоги в Perl) возвращают признак ошибки и присваивают коду ошибки EINTR, Interrupted system call .Проверка этого условия настолько усложняет программу, что во многих случаях это вообще не делается, поэтому при прерывании сигналом медленных системных функций программа начинает вести себя неверно или аварийно завершается. Большинство современных версий UNIX позволяет изменить ход событий. Perl всегда делает системные функции перезапускаемыми, если эта возможность поддерживается системой. В системах POSIX можно управлять перезапуском с помощью модуля POSIX (см. рецепт 16.20).

Чтобы узнать, будет ли ирерванная системная функция автоматически нереза-нущена, загляните в заголовочный файл signal.h вашей системы:

% egrep S[AV] (RESTARTINTERRUPT) /usr/mclude/./signal h



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