Анимация
JavaScript
|
Главная Библионтека полностью игнорируются. Почти для любого сигнала действие по умолчанию может быть переопределено, с тем чтобы данный сигнал либо игнорировался, либо перехватывался (с автоматическим вызовом указанной пользователем части кода). Все это аналогично тому, что делается и в других языках программирования, но сейчас излагаемый материал приобретет специфический Perl-оттенок. Когда Perl-процесс перехватывает сигнал, асинхронно и автоматически вызывается указанная вами подпрограмма, моментально прерывая выполнявшийся до нее код. Когда эта подпрограмма завершается, выполнение прерванного кода возобновляется, как будто ничего не случилось (за исключением появления результатов действий, выполненных этой подпрограммой,- если она вообще что-нибудь делала). Обычно подпрограмма-обработчик сигнала делает одно из двух: прерывает программу, выполнив "очистку", или устанавливает какой-то флаг (например, глобальную переменную), которую данная программа затем проверяет*. Для того чтобы зарегистрировать подпрограммы-обработчики сигналов в Perl, нужно знать имена сигналов. После регистрации обработчика сигнала Perl при получении этого сигнала будет вызывать выбранную подпрограмму. Имена сигналов определяются на тап-странице signal(2), а также, как правило, в подключаемом С-файле /usr/include/sys/signal.h. Эти имена обычно начинаются с букв siG, напрнгмер sigint, sigquit и sigkill. Чтобы объявить пoдпpoгpaммymy sigint catcher () обработчиком сигнала sigint, мы должны установить соответствующее значение в специальном хеше %siG. В этом хеше в качестве значения ключа int (это sigint без sig) следует указать имя подпрограммы, которая будет перехватывать сигнал sigint: $SIG(INT} = my sigint catcher; Но нам понадобится также определение этой подпрограммы. Вот пример простого определения: sub my sigint catcher ( $saw sigint =1; # установить флаг Данный перехватчик сигналов устанавливает глобальную переменную и сразу же возвращает управление. Выполнение программы продолжается с той позиции, в которой оно было прервано. Обычно сначала обнуляется флаг $saw sigint, соответствующая подпрограмма определяется как перехватчик сигнала sigint, а затем следует код основной программы, например: $saw sigint =0; # очистить флаг $SIG{INT} = my sigint catcher; # зарегистрировать перехватчик Попытка выполнения действий более сложных, чем вышеописанные, вероятнее всего, запутает ситуацию; большинство внутренних механизмов Perl "не любят", когда их вызывают одновременно в основной программе и из подпрограммы. Ваши системные библиотеки тоже этого "не любят". foreach (@huge array) ( # что-нибудь сделать # еще что-нибудь сделать # и еще что-нибудь if ($saw sigint) ( # прерывание нужно? # здесь "очистка" last; $SIG(INT} = DEFAULT; # восстановить действие по умолчанию Особенность использования сигнала в данном фрагменте программы состоит том, что значение флага проверяется в важнейших точках процесса вычисления и используется для преждевременного выхода из цикла; при этом выполняется и необходимая "очистка". Обратите внимание на последний оператор в приведенном выше коде: установка действия в значение default восстанавливает действие конкретного сигнала по умолчанию (следующий сигнал sigint немедленно прервет выполнение программы). Еще одно полезное специальное значение вроде этого - ignore, т.е. "игнорировать сигнал" (если действие по умолчанию - не игнорировать сигнал, как у SIGINT). Для сигнала можно установить действие ignore, если не нужно выполнять никакой "очистки" и вы не хотите преждевременно завершать выполнение основной профаммы. Один из способов генерирования сигнала s igint - заставить пользователя нажать на клавиатуре терминала соответствующие прерыванию клавиши (например, [Ctrl+C]). Процесс тоже может генерировать сигнал sigint, используя для этого функцию kill. Данная функция получает номер или имя сигнала и посылает соответствующий сигнал в процессы (обозначенные идентификаторами) согласно списку, указанному после сигнала. Следовательно, для передачи сигнала из программы необходимо определить идентификаторы процессов-получателей. (Идентификаторы процессов возвращаются некоторыми функциями, например функцией fork, и при открытии профаммы как дескриптора файла функцией open). Предположим, вы хотите послать сигнал 2 (известный также как sigint) в процессы 234 и 237. Это делается очень просто: kill(2, 234, 237) ; # послать SIGINT в 234 и 237 kill {INT, 234, 237); # то же самое Более подробно вопросы обработки сигналов описаны в главе 6 книги Programming Perl и на man-странице perlipc(l). Упражнения Ответы к упражнениям см. в приложении А. 1. Напишите программу, которая получает результат команды date и вычисляет текущий день недели. Если день недели - рабочий день, выводить get to work, в противном случае выводить до play. 2. Напишите программу, которая получает все реальные имена пользователей из файла /etc/passwd, а затем трансформирует результат команды who, заменяя регистращгонное имя (первая колонка) реальным именем. (Совет: создайте хеш, где ключ - регистрационное имя, а значение - реальное имя.) Попробуйте выполнить эту задачу с использованием команды who как в обратных кавычках, так и открытой как канал. Что легче? 3. Модифицируйте предьщущую программу так, чтобы ее результат автоматически поступал на принтер. (Если у вас нет доступа к принтеру, то, вероятно, вы можете послать самому себе сообщение электронной почты.) 4. Предположим, функция mkdir перестала работать. Напишите подпрограмму, которая не использует mkdir, а вызывает /bin/mkdir с помощью функции system. (Убедитесь в том, что она работает с каталогами, в именах которых есть пробел.) 5. Расширьте программу из предьщущего упражнения так, чтобы в ней устанавливались права доступа (с помощью функции chmod). 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 |