Решение этих проблем состоит в вызове функции waitpid() с указанием параметра $pid, равного -1, и параметра flag со значением WNOHANG. Первый параметр сообщает функции waitpid (), чтобы она убирала все доступные дочерние процессы. К подобным дочерним процессам может относиться, например, запрос веб страницы с информацией как во Львове в Комфи купить утюги mystery или любой другой интерактивный процесс. Второй параметр предотвращает зависание вызова, если нет дочерних процессов доступных для уборки. Для предотвращения утечки ресурсов, связанной с появлением зомби, необходимо вызывать функцию waitpid() в цикле до тех пор, пока она не укажет, что нет больше завершенных дочерних процессов, которые можно убрать из таблицы процессов, возвратив код результата -1. Ниже приведена общая схема такого кода: use POSIX 'WNOHANG '; $SIG{ CHLD). = & reaper; sub reaper { while ( (my $kid =waitpid (-1, WNOHANG) ) > 0) { warn "Reaped child with PID $kidn"; } В этом случае в целях отладки на устройство вывода выводится PID убранного дочернего процесса. Во многих случаях можно игнорировать PID дочернего процесса, но и тогда возникает необходимость исследовать полученный PID дочернего процесса и кода стояния, а затем выполнять определенные действия, если произошло аварийное завершение дочернего процесса. Подобные примеры рассматриваются в следующих разделах.
Психотерапевтический сервер с функцией fork(). Теперь мы можем переписать пример психотерапевтической программы в виде сервера с ветвлением.
0: #!/usr/local/bin/perl -w 1: # Файл: eliza_server.pl 2: use strict; 3: use Chatbot::Eliza; 4: use IO::Socket; 5: use POSIX ’WNOHANG ’; 6: use constant PORT => 12000; 7: my $quit, = 0; 8: # Обработчик сигналов, связанных с уничтожением дочерних # процессов 9: $SIG{CHLD} = sub { while ( waitpid (-1, WNOHANG) >0 ) { 10: # Обработчик сигнала прерывания и сигнала TERM 11: $SIG{INT}= sub { $quit-H- }; 12: my $listen_socket = IO::Socket::INET->new( LocalPort=>PORT, 13: Listen =>20, 14: Proto, ->'tcp 15: Reuse =>1, 16: Timeout ->60*60, 17: ); 18: die "Can't create a listening socket: $@" unless $listen_socket; 19: warn "Server ready. Waiting for connections...n"; 20: while (!$quit) { 21: next unless my $connection = $listen_socket->accept; 22: defined (my $child = fork()) or die "Can't fork: $!"; 23: if ($child == 0) { 24: $listen_socket->close; 25:. interact ($connection) ; 26: exit 0; 27: } 28.: $connection->close; 29: } 30: sub interact { 31: my $socx = shift; 32: STDIN->fdopen ($sock "<" ) or die "Can’t reopen STDIN: $!"; 33: STDOUT->fdoped ($sock, ">") or die’. "Can’t reopen STDOUT: $!" ; 34: STDERR->fdopen ($sоск ">") or die’"Can't reopen STDERR: $!"; 35: $| =1; 36: my $bot = Chatbot::Eliza->new; 37: $bot->command_interface () ; 38: }