Изучаем Perl

       

Использование функции 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 может иметь необязательный параметр, служащий числовим кодом выхода, который воспринимается родительским процессом. По умолчанию выход производится с нулевым кодом, показывающим, что все прошло нормально.


Содержание раздела