Forum Webscript.Ru

Программирование => Perl => Тема начата: Wells от 26 Октября 2004, 17:17:29

Название: Глобальные переменные и fork
Отправлено: Wells от 26 Октября 2004, 17:17:29
Есть глобальная переменная. Как из процесса-потомка, вызванного через fork, записать в неё какое-то значение? (Всё под Windows)
Название: Глобальные переменные и fork
Отправлено: NeoNox от 26 Октября 2004, 17:28:58
А в чем загвоздка?
Название: Глобальные переменные и fork
Отправлено: Wells от 26 Октября 2004, 18:34:49
Есть следующий код:

use strict;
use Benchmark;
my $tmStamp1 = new Benchmark;
#/////////////////////////////////////////////////////////////////////////////////
$| = 1;
my $threads = 5;
my @pids;
my $isExit = 0;
#/////////////////////////////////////////////////////////////////////////////////
for (1 .. $threads) {
makeChild();
}
print "$isExit\\n";
for (my $i = 0; $i <= ($threads-1); $i++) {
print "$pids[$i]\\n";
waitpid($pids[$i], 0);
}
print "$isExit\\n";
#/////////////////////////////////////////////////////////////////////////////////
my $tmStamp2 = new Benchmark;
my $tmDiffer = timediff($tmStamp1, $tmStamp2);
print timestr($tmDiffer);
#/////////////////////////////////////////////////////////////////////////////////
sub makeChild {
my $pid;
die "fork: $!" unless defined ($pid = fork);
if ($pid) {
push(@pids,$pid);
return;
}
else {
my $i = 0;
for ($i; $i<=10 ; $i++) {
Time::HiRes::sleep(1.0);
}
$isExit = 1;
exit(0);
}
}
#/////////////////////////////////////////////////////////////////////////////////

Так вот $isExit не меняется перед выходом из скрипта
Название: Глобальные переменные и fork
Отправлено: NeoNox от 26 Октября 2004, 19:02:19
Wells а с какой радости он должен меняться?
Вместо того что-бы вываливать кучу ненужного кода разобрался бы в сабе с fork.
Название: Глобальные переменные и fork
Отправлено: NeoNox от 26 Октября 2004, 19:03:38
Вот тебе для внекласного чтения:
use IO::Handle;
use strict;
my ($line, $pid);
autoflush STDOUT;

if ($pid = open(CHILD, "-|")) {
    chomp($line = );
    print $line;
    close(CHILD);
} else {
    die "cannot fork: $!" unless defined $pid;
    print STDOUT "4"; #This value will be sent to $line
    exit;
}
Название: Глобальные переменные и fork
Отправлено: Wells от 27 Октября 2004, 09:34:20
Если бы я сам мог разобраться - сюда не писал бы!!!!
To NeoNox: твой код выдаёт:
\'-\' is not recognized as an internal or external command,
operable program or batch file.
P.S. И какой это я "ненужный" код "вывалил"? Я "вывалил" свой скрипт! И всё!
Название: Глобальные переменные и fork
Отправлено: arto от 27 Октября 2004, 11:34:08
perldoc perlipc
Название: Глобальные переменные и fork
Отправлено: NeoNox от 27 Октября 2004, 11:34:56
Wells
Цитировать
Wells:
И какой это я "ненужный" код "вывалил"?

У тебя непонимание принципа fork.
Строки c 1 по 23 не имеют к твоей проблеме ни малейшего отношения.
Читать
perldoc -f fork
perldoc perlipc
до того как применять мое решение.
Цитировать
Wells:
To NeoNox: твой код выдаёт:

Да, я не учел что ты под виндовсом.
Вот исправленный вариант:
use IO::Handle;
use strict;
pipe(READER, WRITER);
autoflush WRITER;
my ($pid,  $line);

if ($pid = fork) {
    close WRITER;
    chomp($line = );
    print $line;
    close READER;
    waitpid($pid,0);
} else {
    die "cannot fork: $!" unless defined $pid;
    close READER;
    print WRITER "4"; #This value will be sent to $line
    close WRITER;  # this will happen anyway
    exit;
}
Название: Глобальные переменные и fork
Отправлено: Wells от 27 Октября 2004, 15:44:41
To NeoNox: Всё работает! Спасибо! Только я вот не зря весь кусок кода вывалил. У меня там есть цикл, в котором 5 раз вызываются потомки. Так вот, как в конце проверить записал потомок что-то или нет? С одним потомком всё работает! А как с пятью быть???
Название: Глобальные переменные и fork
Отправлено: NeoNox от 27 Октября 2004, 16:24:42
Ну так напиши, в чем проблема?
Или мне все за тебя написать?
Название: Глобальные переменные и fork
Отправлено: Wells от 27 Октября 2004, 16:30:07
To NeoNox: Я понимаю - ты профи и для тебя это туфта, но у меня ничерта не получается! Вот так не работает:

use IO::Handle;
use strict;
my $threads = 5;
pipe(READER, WRITER);
autoflush WRITER;
my ($pid,  $line);
my $threads = 5;
for (my $i = 1; $i <= ($threads); $i++) {
if ($pid = fork) {
    close WRITER;
    chomp($line = );
    #print $line;
    close READER;
    waitpid($pid,0);
}
else {
    die "cannot fork: $!" unless defined $pid;
    close READER;
    print WRITER "4"; #This value will be sent to $line
    close WRITER;  # this will happen anyway
    exit;
}
}
print $line;
Название: Глобальные переменные и fork
Отправлено: NeoNox от 27 Октября 2004, 16:57:42
Лень это хорошо, но понимание сути вопроса - еще лучше.
Перенеси
pipe(READER, WRITER);
autoflush WRITER;
внутрь цикла.
Название: Глобальные переменные и fork
Отправлено: Wells от 27 Октября 2004, 18:41:24
В том то и вопрос, что если в процессе потомке что-то делать, то распаралеливание процессов не получается. Например если в ветку else засунуть

my $i = 0;
for ($i; $i<=10 ; $i++) {
   Time::HiRes::sleep(1.0);
}

то весь скрипт выполняется в пять раз дольше!!!
Название: Глобальные переменные и fork
Отправлено: NeoNox от 27 Октября 2004, 19:11:17
Wells правильно. а ты что хотел от так написанной программы?
Напиши на бумаге логику что должно произойти, а потом напиши это на Perl. Будут вопросы, сначала полностью логику сюда, а потом будем разбираться дальше.
Название: Глобальные переменные и fork
Отправлено: NeoNox от 27 Октября 2004, 19:17:34
1. читаем вдумчиво perldoc -f fork
2. пишем комментарий к каждой строчке в твоей программе
Название: Глобальные переменные и fork
Отправлено: Wells от 28 Октября 2004, 10:53:08
Смысл в следующем:
Пишу сетевой сканер для служебных целей.
Сканируемая сеть около 10000 узлов.
С одним потоком сканирование занимает более 3 часов.
Нужно ускорить этот процес. Решил разбить на 5 потоков (через fork). Процесс ускорился до 45 минут. Но встали проблемы с оповещением.
Алгоритм примерно следующий:
1 - $isAlert = 0;
2 - создание массивов из IP адресов, по количеству потоков сканирования;
4 - создание потоков сканирования (через fork);
5 - для каждого адреса выполняется определённая проверка. Если условие выполняется, то переходим к следующему адресу. Если нет, то нужно $isAlert присвоить 1;
6 - ожидаем окончания работы всех потоков;
7 - формируем лог;
8 - если $isAlert = 1 отправляем лог по почте админу.
9 - выход.
Всё работает. Не могу побороть только пункт 8. Точнее с 1 потоком никаких проблем нет. А больше не идёт!

P.S. PERL\'ом я занялся месяц назад. Так что жду снисхождения.
Название: Глобальные переменные и fork
Отправлено: Wells от 28 Октября 2004, 13:40:08
Решил слепить тоже самое через Thread\'ы.
Получается следующее:

use strict;
use Thread qw(async yield);
my $var = 0;
sub child {
    {
        lock $var;
        if ($var == 0) {
            yield;
            $var++;
            print "var is $var\\n";
        }
    }
}
my $t2 = new Thread \\&child;
$t2->join;
print "var is $var\\n";

Почему в конце $var всё равно принимает старое значение?
Название: Глобальные переменные и fork
Отправлено: NeoNox от 28 Октября 2004, 14:43:09
Если уж ты на тредах решил делать (на мой взгляд это правильно) взгляни http://www.unix.org.ua/orelly/perl/prog3/ch17_02.htm
На пример  17.2.2.3. Locking subroutines