Добрый день. Я сейчас прохожу курс повышения квалификации - "Профессиональное веб-программирование". Мне нужно получить диплом по этому курсу. Я так полагаю нужно его оплатить чтобы получить диплом о повышении квалификации. Как мне оплатить этот курс?
|
Взаимодействие процессов
Замена текущего процесса
Иногда требуется организовать выполнение программы таким образом: вначале запускается загрузчик, который, в зависимости от условий, заданных в конфигурации программы, запускает вместо себя основную программу. Этот подход можно реализовать с помощью функции exec, которая заменяет работающую программу на указанную. Так можно запускать не только Perl-программы. Этот прием можно проиллюстрировать таким примером:
print "Выполняется загрузчик: $0, PID:$$\n"; # заменить текущую программу на указанную my $program = $ARGV[0]; # имя программы в 1-м аргументе print "Запускается программа: $program\n"; exec 'perl', $program or die; # запуск программы print "Это сообщение никогда не напечатается!\n";
При запуске этого примера с параметром 'proc_executed.pl' будут выведены такие сообщения:
Выполняется загрузчик: proc_exec.pl, PID:652 Запускается программа: proc_executed.pl Выполняется программа: proc_executed.pl, PID:1872
Параллельное выполнение процессов
Для организации параллельного выполнения процессов в Perl используется функция fork ("разветвить"). В результате ее работы создается копия выполняющегося процесса, которая тоже запускается на выполнение. Для этого в операционных системах семейства Unix происходит обращение к системному вызову fork. В других операционных системах работа функции fork() организуется исполняющей системой Perl. Функция fork() в родительском процессе возвращает PID дочернего процесса, число 0 - в дочернем процессе и неопределенное значение при невозможности запустить параллельный процесс. Это значение проверяется в программе, чтобы организовать выполнение различных действий в процессе-предке и процессе-потомке. Как это делается, показано на следующем схематичном примере (где оба процесса в цикле выводят числа, но с разными задержками):
my $pid = fork(); # 'разветвить' текущий процесс # fork вернет 0 в потомке и PID потомка в процессе-предке die "fork не отработал: $!" unless defined $pid; unless ($pid) { # процесс-потомок print "Начался потомок PID $$\n"; for (1..3) { print "Потомок PID $$ работает $_\n"; sleep 2; # 'заснуть' на 2 секунды } print "Закончился потомок PID $$\n"; exit; } if ($pid) { # процесс-предок print "Начался предок PID $$\n"; for (1..3) { print "Предок PID $$ работает $_\n"; sleep 1; # 'заснуть' на 1 секунду } # возможно, здесь нужно ждать завершения потомка: # print "Предок PID $$ ждет завершения $pid\n"; # waitpid $pid, 0; print "Закончился предок PID $$\n"; }
По сообщениям, выводимым при выполнении этого примера, видно, что родительский и порожденный процессы выполняются параллельно. Для того чтобы организовать в родительском процессе ожидание завершения дочернего процесса, применяется функция waitpid(), которой передается PID процесса-потомка (а также, возможно, дополнительные параметры). По выдаваемым сообщениям сравните два варианта выполнения приведенной выше программы - без ожидания завершения дочернего процесса и с ожиданием завершения процесса-потомка (для этого нужно раскомментарить вызов функции waitpid ):
Без ожидания потомка С ожиданием потомка по waitpid() ---------------------------- -------------------------------- Начался потомок PID -1024 Начался потомок PID -1908 Потомок PID -1024 работает 1 Потомок PID -1908 работает 1 Начался предок PID 1504 Начался предок PID 1876 Предок PID 1504 работает 1 Предок PID 1876 работает 1 Предок PID 1504 работает 2 Предок PID 1876 работает 2 Потомок PID -1024 работает 2 Потомок PID -1908 работает 2 Предок PID 1504 работает 3 Предок PID 1876 работает 3 Закончился предок PID 1504 Предок PID 1876 ждет завершения -1908 Потомок PID -1024 работает 3 Потомок PID -1908 работает 3 Закончился потомок PID -1024 Закончился потомок PID -1908 Закончился предок PID 1876
Выполнение всей программы заканчивается, когда заканчивается последний порожденный процесс. Ожидание окончания выполнения всех дочерних процессов можно организовать с помощью функции wait(), которая возвращает PID завершившегося подпроцесса и -1, если все процессы-потомки завершили работу.
Взаимодействие подпроцессов
В Perl есть несколько способов организации взаимодействия процессов при их параллельном выполнении. Один из них - создать программный канал (pipe), который представляет из себя два файловых манипулятора - приемник (reader) и передатчик (writer) - связанных таким образом, что записанные в передатчик данные могут быть прочитаны из приемника. Программный канал создается с помощью функции pipe(), которой передаются имена двух файловых манипуляторов: приемника и источника. Один из вариантов взаимодействия процессов через программный канал показан в следующем примере:
use IO::Handle; # подключаем стандартный модуль pipe(READER, WRITER); # создаем программный канал WRITER->autoflush(1); # включаем авто-очистку буфера if ($pid = fork()) { # процесс-предок получает PID потомка close READER; # предок не будет читать из канала print WRITER "Послано предком (PID $$):\n"; for (my $n = 1; $n <= 5; $n++) { # запись в передатчик print WRITER "$n "; } close WRITER; # закрываем канал и waitpid $pid, 0; # ждем завершения потомка } die "fork не отработал: $!" unless defined $pid; if (!$pid) { # процесс-потомок получает 0 close WRITER; # предок не будет писать в канал print "Потомок (PID $$) прочитал:\n"; while (my $line = <READER>) { # чтение из приемника print "$line"; } close READER; # канал закрывается exit; # потомок завершает работу }
Во время выполнения этого примера в стандартный выходной поток будет выведено следующее:
Потомок (PID -2032) прочитал: Послано предком (PID 372): 1 2 3 4 5
Если нужно организовать передачу данных в обратном направлении, организуется канал, в котором передатчик будет в процессе-потомке, а приемник - в процессе-предке. Так как с помощью программного канала можно передавать данные только в одном направлении, то при необходимости двустороннего обмена данными между процессами создаются два программных канала на передачу в обоих направлениях.
Кроме программных каналов, процессы могут обмениваться информацией и другими способами: через именованные каналы (FIFO) и разделяемые области памяти, если они поддерживаются операционной системой, с помощью сокетов (что будет рассмотрено в следующей лекции) и при помощи сигналов.