Добрый день.
Возникла проблемма с pipe в перле.
есть код, в котором происходит fork на два процесса. в дочернем процессе происходит обработка некоторых команд и через pipe данные передаются родителю. примерно так
pipe(PARENT,CHILD);
PARENT->autoflush(1);
my @arr=();
$pid=fork;if($pid==0)
{
close $CHILD;
здесь формируется массив @arr
foreach my $send_msg (@arr)
{ print PARENT $send_msg;
}
close PARENT;
exit;
}
else
{
close PARENT;
while(my $recv_msg=<CHILD>)
{
push @arr,$recv_msg;
}
waitpid($pid,0);
}
проблема собственно в том, что при больших размерах массива @arr(килобайт 80) происходит зависание. точнее происходит следующее: чилд в цикле закладывает в пайп данные, после чего завершается. парент вычитывает данные из пайпа после завершения чилд процесса. при больших объемах информации переполняется пайп и чилд виснет. парент ждет завершения чилда и тоже висит.необходимо реализовать такую схему: чилд положил данные в пайп, парент увидел что данные пришли вычитал их, опустил к примеру семафор, чилд увидел, что семафор опущен и положил еще кусочек данных в пайп. таким образом переполнения не произойдет никогда.
НО. я не пойму как одновременно заставить работать чилда и парента. у меня получается, что пока чилд не завершит свою работу, парент не начнется.
>[оверквотинг удален]
>$pid=fork;
>
>if($pid==0)
>{
> close $CHILD;
>здесь формируется массив @arr
> foreach my $send_msg (@arr)
> { print PARENT $send_msg;
> }
>pipe READHANDLE,WRITEHANDLE
Opens a pair of connected pipes like the corresponding system call. Note that if you set up a loop of piped pro-
cesses, deadlock can occur unless you are very careful. In addition, note that Perl's pipes use IO buffering, so you
may need to set $| to flush your WRITEHANDLE after each command, depending on the application.как это вообще у тебя работает??? ты печатаешь в хендл для чтения!
>[оверквотинг удален]
>
> cesses, deadlock can occur unless you are very
>careful. In addition, note that Perl's pipes use IO buffering,
>so you
>
> may need to set $| to flush your
>WRITEHANDLE after each command, depending on the application.
>
>как это вообще у тебя работает??? ты печатаешь в хендл для чтения!
>суть не в том! это я на форуме печатаю в хендл для чтения :)) спасибо за поправку конечно :)
но хотелось бы ответа по теме вопроса :)
>[оверквотинг удален]
>>
>> may need to set $| to flush your
>>WRITEHANDLE after each command, depending on the application.
>>
>>как это вообще у тебя работает??? ты печатаешь в хендл для чтения!
>>
>
>суть не в том! это я на форуме печатаю в хендл для
>чтения :)) спасибо за поправку конечно :)
>но хотелось бы ответа по теме вопроса :)У меня ничего не виснет, файл кило 100 улетат мгновенно. ничего не переполняется.
вот слегка модифицированый(до рабочего) твой же код:
#!/usr/bin/perl
use IO::File;
use File::Spec;use strict;
sub print_arr {
my @t = @_;
foreach my $l (@t) {
print $l;
}
}pipe(CHILD, PARENT);
CHILD->autoflush(1);
my @arr=();
my $delim = '---------------------------------------------------------------------------'."\n";
print "Single process work\n";
my $pid=fork;if($pid==0) {
#Child work, children process read file, to arr, and send to parent
close CHILD;
print "Child process work: $$\n";
#здесь формируется массив @arr
open(F_IN, "<", 'arr.txt');
while(my $t = <F_IN>) {
push @arr, $t;
}
close(F_IN);
print "Child Process: makes array:\n";
print "Child Process:".$delim;
print_arr(@arr);
print "Child Process:".$delim;
foreach my $send_msg (@arr){
print PARENT $send_msg;
}
close PARENT;
exit;
}
else {
#Parent work, parent process read data from pipe child and make array, after all read print
print "Parent process work: $$, child: $pid\n";
$SIG{CHLD} = "IGNORE";
close PARENT;
while(my $recv_msg=<CHILD>) {
push @arr,$recv_msg;
}
print "Parent Process:".$delim;
print_arr(@arr);
print "Parent Process:".$delim;#waitpid($pid,0);
}
привет.
да, действительно. этот код рабочий!
и если в моем реальном коде оставить один пайп, то тоже все работает. но у меня немного другая ситуация. у меня четыре пайпа и вот примерно так это выглядит:#!/usr/bin/perl
use IO::File;
use File::Spec;
use POSIX;
use strict;sub print_arr {
my @t = @_;
foreach my $l (@t) {
print $l;
}
}pipe(CHILD, PARENT);
pipe(R1,W1);
pipe(R2,W2);
pipe(R3,W3);
R1->autoflush(1);
R2->autoflush(1);
R3->autoflush(1);
CHILD->autoflush(1);
my @arr=();
my $delim = '---------------------------------------------------------------------------'."\n";
print "Single process work\n";
my $pid=fork;if($pid==0) {
#Child work, children process read file, to arr, and send to parent
close CHILD;close R1;close R2;close R3;
print "Child process work: $$\n";
#здесь формируется массив @arr
print W1 "1";
open(F_IN, "<", '/var/log/nortel/linuxbase.log');
while(my $t = <F_IN>) {
push @arr, $t;
}
close(F_IN);
print "Child Process: makes array:\n";
print "Child Process:".$delim;
# print_arr(@arr);
print scalar @arr;
print "Child Process:".$delim;
my $count=1;
foreach my $send_msg (@arr){
print PARENT $send_msg;
print "'$count'{child}\n";$count++;
}
close PARENT;
close W1;close W2;close W3;
_exit(0);
}
else {
#Parent work, parent process read data from pipe child and make array, after all read print
print "Parent process work: $$, child: $pid\n";
$SIG{CHLD} = "IGNORE";
close PARENT;
close W1;close W2;close W3;
my $read1=<R1>;
print "'$read1'\n";
while(my $recv_msg=<CHILD>) {
push @arr,$recv_msg;
}
print "Parent Process:".$delim;
# print_arr(@arr);
print scalar @arr;
print "Parent Process:".$delim;
close CHILD;
close R1;close R2;close R3;
waitpid($pid,0);
}данный код уже висит.
можно как-либо увеличить количество памяти, которое отводиться под пайпы? как я понимаю, оно всегда постоянно и равно, допустим, COUNT_MEM и если открывается пять пайпов то на каждый пайп отводится COUNT_MEM/5 byte.
ps или я несу полную чушь? :)))
please help :)
pps. последнее, говорит child: '602'{child}, тоесть он отправил 602 сообщения в пайп.
>[оверквотинг удален]
>}
>
>данный код уже висит.
>можно как-либо увеличить количество памяти, которое отводиться под пайпы? как я понимаю,
>оно всегда постоянно и равно, допустим, COUNT_MEM и если открывается пять
>пайпов то на каждый пайп отводится COUNT_MEM/5 byte.
>ps или я несу полную чушь? :)))
>please help :)
>pps. последнее, говорит child: '602'{child}, тоесть он отправил 602 сообщения в пайп.
>понятно что висит, вы записали один байт в W1 а в парент процессе ждете что вам придет целая строка из R1. либо пишите "1\n" либо читайте один байт.
и не заморачивайтесь размером буферов. не в них дело.
не знаю как у меня затесался этот код:
pipe(CHILD, PARENT);
CHILD->autoflush(1);
но он совершенно не верен!!!
он просто не имеет смысла! он как раз и устанавливает размер буфера при котором происходит автоматический сброс буферов, при заполнении буфера размером 1.
но этот дескриптор на чтение, и устанавливать там размер буфера бессмысленно.
надо было поставить:
PARENT->autoflush(1);
тогда размер буфера, на запись не превышал бы 1 символа, и данные передавались бы практически сразу.но поскольку у вас происходит обмен строками все эти установки не особо важны(даже вредны, т.к. излишне нагружают систему)
>понятно что висит, вы записали один байт в W1 а в парент
>процессе ждете что вам придет целая строка из R1. либо пишите
>"1\n" либо читайте один байт.СПАСИБО! человеческое и огромное :)))) я б быстрее организовал еще пару процессов и семафоры, что б родитель сигнализировал, что получены данные и чилд после этого отсылал следующую порцию, чем понял бы что дело в строках :)
лучше меньше, да лучше(с) как говорил вождь :)>и не заморачивайтесь размером буферов. не в них дело.
угу.
>не знаю как у меня затесался этот код:
>pipe(CHILD, PARENT);
>CHILD->autoflush(1);
>но он совершенно не верен!!!
>он просто не имеет смысла! он как раз и устанавливает размер буфера
>при котором происходит автоматический сброс буферов, при заполнении буфера размером 1.вот здесь я не очень понял, тоесть при таком подходе в пайп будет передаваться по одному байту за раз?
>но этот дескриптор на чтение, и устанавливать там размер буфера бессмысленно.
>надо было поставить:
>PARENT->autoflush(1);это понятно :)))
Спасибо!
>>не знаю как у меня затесался этот код:
>>pipe(CHILD, PARENT);
>>CHILD->autoflush(1);
>>но он совершенно не верен!!!
>>он просто не имеет смысла! он как раз и устанавливает размер буфера
>>при котором происходит автоматический сброс буферов, при заполнении буфера размером 1.
>
>вот здесь я не очень понял, тоесть при таком подходе в пайп
>будет передаваться по одному байту за раз?Скажем, так, я наврал. и перепутал логическую перемнную, с размером.
>>он просто не имеет смысла! он как раз и устанавливает размер буфера
>>при котором происходит автоматический сброс буферов, при заполнении буфера размером 1.
>
>вот здесь я не очень понял, тоесть при таком подходе в пайп
>будет передаваться по одному байту за раз?
>суть (auttoflush)в том что данные будут передаваться каждый раз после print(вообщем после записи в пайп). если вывел 1 байт, передастся 1 байт.
вобщем если нужно поставь.только что бы это увидеть нужно вывод(отладочный) также сделать не буферизированным, если отладка идет stdout то так:
STDOUT->autoflush(1);
еще раз спасибо за разъяснения :)