Использование функции fork
Еще один способ создания нового процесса — клонирование текущего Perl-процесса с помощью UNIX-функции fork. Функция fork делает то же самое, что и системний вызов fork(2): создает клон текущего процесса. Зтот клон (он называется порожденным процессом, а оригинал — родительским) использует тот же выполняемый код, те же переменные и даже те же открьггые файлы. Различаются зти два процесса по возвращаемому значенню функции fork: для порожденного процесса оно равно нулю, а для родительского — ненулевое (или undef, если зтот системний вызов окажется неудачним). Ненулевое значение, получаемое родительским процессом,— зто не что иное как идентификатор порожденного процесса. Ви можете проверить возвращае-мое значение и действовать соответственно:
if (!defined($child_pid = fork()) {
die "cannot fork: $!";
} elsif ($pid) {
4s я —
родительский процесе } else (
# я — порожденннй процесе >
Чтоби максимально зффективно использовать зтот клон, нам нужно изучить еще несколько функции, которьге восьма похожи на своих UNIX-тезок: зто функции wait, exit и ехес.
Самая простая из них — функция ехес. Зто почти то же самое, что и функция system, за тем исключением, что вместо запуска нового процесса для виполнения shell-команди Perl заменяет текущий процесе на shell. После успешного внполнения ехес Perl-программа исчезает, поскольку вместо нее виполняется затребованная программа. Например,
ехес "date";
заменяет текущую Perl-программу командой date, направляя результат зтой команди на стандартний вивод Perl-программи. После завершення команди date делать больше нечего, потому что Perl-программа давно исчезла.
Все зто можно рассматривать и по-другому: функция system похожа на комбинацию функции fork c функцией ехес, например:
# МЕТОД І... использование system:
system("date");
t МЕТОД 2... использование fork/exec:
unless (fork) (
# fork видала нуль, позтому я — порожденный процесе и я выполняю:
exec ("date") ; t порожденный процесе становится командой date
}
Использовать fork и exec таким способом — не совсем правильно, потому что команда date и родительский процесе "пыхтят" одновременно, их результати могут переметаться и испортить все дело. Как дать родительскому процессу указание подождать, пока не завершится порожденный процесе? Именно зто и делает функция wait; она ждет завершення данного (да и любого, если быть точним) порожденного процесса. Функция waitpid более разбор-чива: она ждет завершення не любого, а определенного порожденного процесса:
if (!defined($kidpid = fork()) (
# fork возвратила undef, т.е. неудача die "cannot fork: $!";
” elsif ($pid =" 0) {
# fork возвратила О, позтому данная ветвь — порожденный процесе exec("date") ;
# если exec терпит неудачу, перейти к следующему оператору die "can't exec date: $!";
} else {
# fork возвратила не 0 и не undef,
# позтому данная ветвь — родительский процесе waitpid($kidpid, 0) ;
}
Если все зто кажется вам слишком сложным, изучите системные вызовы fork(2) и ехес(2), отыскав материалы о них в каком-нибудь руководстве по ОС UNIX, потому что Perl просто передает вызовы зтих функций прямо в системные вызовы UNIX.
Функция exit обеспечивает немедленньш выход из текущего Perl-про-цесса. Она используется для прерывания Perl-программы где-нибудь посе-редине или — вместе с функцией fork — для вьшолнения Perl-кода в процессе с последующим выходом. Вот пример удаления нескольких файлов из каталога///?у? в фоновом режиме с помощью порожденного Perl-процесса:
unless (defined ($pid = fork)) ( die "cannot fork: $!";
}
unless ($pid) (
unlink </tmp/badrock.*>; # удалить зти файлн exit; # порожденный процесе останавливается здесь
)
# родительский процесе продолжается здесь
waitpid($pid, 0); # после уничтожения порожденного процесса нужно все убрать
Без использования функций exit порожденный процесе продолжал бы вьшолнять Perl-код (со строки "# родительский процесе продолжается здесь") — а как раз зтого нам и не нужно.
Функция exit может иметь необязательный параметр, служащий числовим кодом выхода, который воспринимается родительским процессом. По умолчанию выход производится с нулевым кодом, показывающим, что все прошло нормально.