| Содержание | Предисловие | В

Глава 14

    В этой главе:


Управление процессами

Использование функций system u ехес

Когда вы из командной строки shell задаєте выполнение какой-либо команды, он обычно создает новый процесе. Зтот новый проц

Аналогичным образом Perl-программа в состоянии запускать новые процессы и может делать зто, как и большинство других операций, несколь-кими способами.

Самий простой способ запуска нового процесса использовать для зтого функцию system. В простейшей форме зта ф

system("date");

Здесь мы не проверяем возвращаемое значение, но неудачный исход выполнения команд н date вряд ли возможен.

Куда идет результат зтой команди? Откуда поступают исходные данные, если они нужны команде? Хорошие вопросы, и ответы на них позволят узнать, чем отличаются различные способы создания процессов.

* В данном случае shell фактически не используется, поскольку Рсгі сам выполняет операций

Три стандартних файла для функции system (стандартний ввод, стандартний внвод и стандартний вивод ошибок) наследуются от Perl-проц

system("date >right_now") && die "cannot create right_now";

На зтот раз ми не только посилаєм результат команди date в файл, внполняя переадресацию в shell,

Аргументом функции system может бить все, что пригодно для передачи в /Ып/sh, позтому можно задавать ср

Вот пример задания команд date и who в

$where = "who_out.".++$і; t получить новое имя файла system "(date; who) >$where &";

В зтом случае функция system возвращает код выхода shell и пока

Помимо стандартних дескрипторов файлов, порожденний процесе на-следует от родительского процесса много других вещей. Зто текущее значение, заданное командой umask, те

Кроме того, порожденний процесе наследует все переменнне среды. Зти переменные обычно изменяются командой csh setenv или же соответствующим В Perl предусмотрена возможность проверки и изменения текущих пере-менных среды посредством специального хеша, который называется %env. Вот простая программа, которая работает, как printenv:

foreach $key (sort keys %ENV) ( print "$key = $ENV($key)\n";

> . ,

Обратите внимание: знак равенства здесь зто не символ операции присваивания, а просто текстовый символ, с помощью которого функц

Вот фрагмент программы, с помощью которого значение переменной path изменяется таким образом, чтобы поиск команды

$oldPATH = $ENV{ "PATH"); # сохранить предыдущий путь $ENV("PATH") = "/bin:/usr/bin:/usr/ucb"; # ввести

Как много текста придется набирать! Гораздо быстрее будет просто установить локальнеє значение для зтого злемента хеша.

Несмотря на наличие некоторых недостатков, операция local может делать одну вещь, которая не под силу операции ту: она способна присваи-вать временное значение одному злемен

{

local $ENV{"PATH"> " "/bin:/usr/bin:/usr/ucb"; ! systemC'grep fred bedrock >output");

>

Функция system может принимать не один аргумент, а список аргумен-тов. В зтом случае Perl не передает список аргументов в

system "grep 'fred flintstone' buffaloes"; # с использованием shell system "grep","fred flintstone","buffaloes"; # без испол

Применение в функции system списка, а не одной строки, зкономит также один процесе shell,Вот еще один пример зквивалентных форм:

Ocfiles = ("fred.c","barney.c"); # что компилировать Soptions = ("-DHARD","-DGRANITE"); # опции

Использование обратных кавычек

Еще один способ запуска процесса заключить командную строку для /Ып/sh в обратные кавычки. Как и в

$now = "the time is now".'date'; # получает текст и дату

Значение переменной $now теперь представляет собой текст the time is now

the time is now Fri Aug 13 23:59:59 PDT 1996

Если взятая в обратные кавычки команда используется не в скалярном, а в списочном контексте, то возвращается список строкових значений, каждое из которых представляет собой строку (оканчивающую

merlyn tty42 Dec 7 19:41 fred ttylA Aug 31 07:02 barney ttylF Sep 1 09:22

Вот как можно получить зтот результат в списочном контексте:

foreach $_ ('who') ( # один раз для каждой строки текста из who <$who,$where,$when) = /(\S+)\s+(\S+)\s+(.*)/;

print "$who on $where at $when\n";

}

* Или символом, которьш у вас занесен в переменную $/.

При каждом выполнении зтого цикла используется одна строка виход-ных данных команди who, потому что взятая в обратные кавич

Стандартний ввод и стандартний вывод ошибок команди, взятой в обратные кавички, наследуются от Perl-процесса*. Зто значит, что обычно стандартний вывод таких команд ви можете получить как значение строки, заключенной в обратные кавички.

die "rm spoke!" if 'rm fred 2>&1';

Здесь Perl-процесе завершается, если rm посылает какое-нибудь сообще-ние

Использование процессов как дескрипторов файлов

Следующий способ запуска процесса создание процесса, которий вигля-дит как дескриптор файла (аналогично библиотечной под

open(WHOPROC, "who 1"); # открнть who для чтения

Обратите внимание на вертикальную черту справа от who. Зта черта информирует Perl* На самом деле все не так просто. См. соответствующий ответ в разделе 8 сборника часто задаваемых вопросов

** Ho не одновременно. Примеры двунаправленной связи приведены в главе 6 книги Programming Perl

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

Аналогичннм образом для запуска команды, которой необходимы вход-ные данные, мы можем открыть дескриптор файла процесса для записи, поставив вертикальную черту слева от команды, например:

open(LPR,"|Ipr -Psiatewriter") ;

print LPR Srockreport;

close(LPR) ;

В атом случае после открытия lpr мы записываем в него данные и закриваєм данный файл. Открьггие процесса с дескриптором файла позв

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

open(LPR,"|Ipr -Psiatewriter >/dev/null 2>&1");

С помощью операций >/dev/null обеспечивается отбраснвание стандартного вивода путем переадресации его на нулевое устройство. Оп

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

open (WHO,"who[ ") ;

open (LPR,"|Ipr - Psiatewriter");

while (<WHO>) (

unless (/fred/) { # не показывать имя Фред print LPR $_:

> } close WHO;

close LPR;

Считивая из дескриптора who по одной строке, зтот фрагмент кода выводит в дескриптор lpr

Вовсе не обязательно указывать в команде open только по одной команде за один прием. В ней можно задать сразу весь конвейєр. Напри

open(WHOPR, "Is I tail -r I");

Использование функции fork

Еще один способ создания нового процесса клонирование текущего Perl-процесса с помощью UNIX-функции

if (!defined($child_pid = fork()) {

die "cannot fork: $!";

} elsif ($pid) {

4s я — родительский процесе } else (

# я порожденннй процесе >

Чтоби максимально зффективно использовать зтот клон, нам нужно изучить еще несколько функции, которьге восьма похожи на своих UNIX-тезок: зто функции wait, exitСамая простая из них функция ехес. Зто почти то же самое, что и функция system, за тем исключением, что вмес

ехес "date";

заменяет текущую Perl-программу командой date, направляя результат зтой команди на стандартний вивод Perl-программи. После

Все зто можно рассматривать и по-другому: функция system похожа на комбинацию функции fork c функцией ехес, на

# МЕТОД І... использование system:

system("date");

t МЕТОД 2... использование fork/exec:

unless (fork) (

# fork видала нуль, позтому я порожденный процесе и я выполняю:

exec ("date") ; t порожденный процесе становится командой date

}

Использовать fork и exec таким способом

if (!defined($kidpid = fork()) (

# fork возвратила undef, т.е. неудача ” elsif ($pid =" 0) {

# fork возвратила О, позтому данная ветвь порожденный процесе

# если exec терпит неудачу, перейти к следующему оператору

} else {

# fork возвратила не 0 и не undef,

# позтому данная ветвь родительский процесе waitpid($k

}

Если все зто кажется вам слишком сложным, изучите системные вызовы fork(2) и ехес(2),

Функция exit обеспечивает немедленньш выход из текущего Perl-про-цесса. Она используется для прерывания Perl-программы где-нибудь

unless (defined ($pid = fork)) ( die "cannot fork: $!";

}

unless ($pid) (

unlink </tmp/badrock.*>; # удалить зти файлн exit; # порожденный процесе останавливается здесь

)

# родительский процесе продолжается здесь

waitpid($pid, 0); # после уничтожения порожденного процесса нужно все убрать

Без использования функций exit порожденный процесе продолжал бы вьшолнять Perl-код (со строки "# родительский процесе продолжается

Функция exit может иметь необязательный параметр, служащий числовим кодом выхода, который воспринимается родительским процессом. По умолчанию выход производится с нулевым ко

Сводка операций, проводимых над процессами

Операции, служащие для запуска процессов, перечислены в таблице 14.1. Таблица 14.1.

Операция

Стандартний ввод

Стандартний

вывод

Стандартний вывод ошибок

Нужно ли ожидать завершення процесса

System()

Наследуется

Наследуется

Наследуется

Да

 

 

от программы

от программы

от программы

 

 

Строка в обратных

Наследуется от программы

Принимается как строковое

Наследуется от программы

Да

кавычках

 

 

значение

 

 

 

 

Запуск

Соединен с

Наследуется

Наследуется

Только во

процесса как деск

дескриптором файла

от программы

от программы

время вы-полнения

риптора файла для

 

 

 

 

 

 

close ()

вывода при

 

 

 

 

 

 

 

 

помощи

 

 

 

 

 

 

 

 

команди

 

 

 

 

 

 

 

 

open()

 

 

 

 

 

 

 

 

Запуск

Наследуется

Соединен с

Наследуется

Только во

процесса как деск

от программы

дескриптором файла

от программы

время вы-полнения

риптора файла для

 

 

 

 

 

 

close ()

ввода при

 

 

 

 

 

 

 

 

помощи

 

 

 

 

 

 

 

 

команди

 

 

 

 

 

 

 

 

open()

 

 

 

 

 

 

 

 

fork,

Выбирается

Выбирается

Выбирается

Выбирается

ехес,

пользователем

пользователем

пользователем

пользователем

wait,

 

 

 

 

 

 

 

 

waitpid

 

 

 

 

 

 

 

 

 

Самый простой способ создать процесе использовать для зтого функ-цию system.Простой способ получить асинхронний процесе (процесе, который по-зволяет продолжать выполнение Perl-программы до своего завершення)открыть команду как дескриптор файла с

Самый гибкий способ запустить процесе заставить программу вызвать функции fork, ехес и w

Передача и прием сигналов

Один из вариантов организации межпроцессного взаимодействия осно-ван на передаче и приеме сигналов. Сигнал зто одноразря

Ответ на сигнал называется действием сигнала. Фиксированные сигналы выполняют определенные действия по умолчанию, например, осуществляют прерывание или приостановку процесса. Остальные сигналы по умолчанию

* Полезно таюке знать о формах типа open(STDERR, ">&stdout") , используемых для точной настройки деск

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

Все зто аналогично тому, что делается и в других языках программиро-вания, но сейчас излагаемый материал приобретет специфический Perl-от-тенок. Когда Perl-процесе перехватывает сигнал, асинхронне и автоматиче-ски вызывается указанная в

Обычно подпрограмма-обработчик сигнала делает одно из двух: преры-вает программу, выполнив "очистку", или устанавливает какой-то флаг (например, глобальную переменную), которую данная программа затем проверяет*.

Для того чтобы зарегистрировать подпрограммы-обработчики сигналов в Perl, нужно знать имена сигналов. После регистрации обработчика сигнала PerlИмена сигналов определяются на man-странице signal(2), а также, как правило, в подключаемом С-файле /usr/include/sys/signal.h.

$SIG{'INT'} ” 'my_sigint_catcher';

Но нам понадобится также определение зтой подпрограммы. Вот пример простого определения:

sub my_sigint_catcher (

$saw_sigint = 1; # установить флаг }

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

$saw_sigint = 0; # очистить флаг $SIG{'INT') = 'my_sigint_catcher'; # зарегистрировать перехватчик

foreach (@huge_array) (

# что-нибудь сделать

t еще что-нибудь сделать

# и еще что-нибудь if ($saw_sigint) ( # прерывание нужно?

t здесь "очистка" last;

} } $SIG('INT'} = 'DEFAULT'; # восстановить действие по умолчанию

* Попытка вьшолнения действий более сложных, чем вышеописанные, вероятнее всего, запутает ситуацию; большинство внутренних механизмов Perl

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

Один из способов генерирования сигнала sigint — заставить пользователя нажать на клавиатуре терминала соответствующие прерыванию клавиши (на-пример, [Ctr

kill(2,234,237); # послать SIGINT в

Более подробно вопросы обработки сигналов описаны в главе 6 книги Programming Perl

Упражнения

Ответы к упражнениям см. в приложении А.

Напишите программу, которая получает результат команды date и вычис-ляет текущий день недели. Если день недели

Напишите программу, которая получает все реальнне имена пользователей из файла /etc/passwd, а затем трансформирует результа

создайте хеш, где ключ регистрационное имя, а значение реальное имя.) Попробуйте вьшолнить зту задачу с ис

Модифицируйте предыдущую программу так, чтобы ее результат автомати-чески поступал на принтер. (Если у вас нетдоступа к принтеру, то, вероятно, вы можете послать самому себе сообщение злектронной почты.)

Предположим, функция mkdir перестала работать. Напишите подпро-грамму, которая не использует mkdir, а вызывает

Расширьте программу из предыдущего упражнения так, чтобы в ней устанавливались права доступа (с помощью функции chmod).




|     Назад     | &n
| Содержание | Предисловие | В



Сайт создан в системе uCoz