Wait for background processes to complete

Greetings,
Well - I've spent a bunch of time trying to figure this out - to no
avail.

Here's what I want to do - run several commands in the background and
have the perl program wait for the commands to complete. Fork doesn't
do it, nor does wait nor waitpid.

Any thoughts?

Here's a sample program which starts the processes:

while (<*.txt>)
{
print "Copying $_ \n";
system("cp $_ $_.old &") ;
}
print "End of excercise\n";
exit;

I mean if this were a shell program - this would work:

for x in `ls *.txt`
do
print "Copying $_ \n"
cp $_ $_.old &
done
wait

thanks,
pg
pgodfrin [ Mo, 14 Januar 2008 04:08 ] [ ID #1907725 ]

Re: Wait for background processes to complete

pgodfrin <pgodfrin [at] gmail.com> wrote:
> Greetings,
> Well - I've spent a bunch of time trying to figure this out - to no
> avail.
>
> Here's what I want to do - run several commands in the background and
> have the perl program wait for the commands to complete. Fork doesn't
> do it, nor does wait nor waitpid.

None of them individually do it, no. You have to use them together.

>
> Any thoughts?
>
> Here's a sample program which starts the processes:
>
> while (<*.txt>)
> {
> print "Copying $_ \n";
> system("cp $_ $_.old &") ;

This starts a shell, which then starts cp in the background. As soon as
the cp is *started*, the shell exits. So Perl has nothing to wait for, as
the shell is already done (and waited for) before system returns. You need
to use fork and system or fork and exec. Or you could use
Parallel::ForkManager, which will wrap this stuff up nicely for you and
also prevent you from fork-bombing your computer if there are thousands of
*.txt

> }
> print "End of excercise\n";
> exit;

1 until -1==wait(); # on my system, yours may differ


Xho

--
-------------------- http://NewsReader.Com/ --------------------
The costs of publication of this article were defrayed in part by the
payment of page charges. This article must therefore be hereby marked
advertisement in accordance with 18 U.S.C. Section 1734 solely to indicate
this fact.
xhoster [ Mo, 14 Januar 2008 04:43 ] [ ID #1907728 ]

Re: Wait for background processes to complete

Quoth pgodfrin <pgodfrin [at] gmail.com>:
>
> Here's what I want to do - run several commands in the background and
> have the perl program wait for the commands to complete. Fork doesn't
> do it, nor does wait nor waitpid.
>
> Any thoughts?
>
> Here's a sample program which starts the processes:
>
> while (<*.txt>)
> {
> print "Copying $_ \n";
> system("cp $_ $_.old &") ;

This string contains a shell metachar (&), so system will fork a shell
and wait for it. The shell will run cp in the background, and then exit,
at which point system will return. Unfortunately, the only process which
knew cp's pid was the shell, which has just exitted, so you can't wait
for that process at all (cp now has init as its parent, like any other
orphaned process).

You need to either implement the behaviour you want with fork, exec and
waitpid (it's a little complicated, but entirely possible) or use
IPC::Run, something like

use IPC::Run qw/run/;

my [at] cmds;

while (<*.txt>) {
print "Copying $_\n";
push [at] cmds, [cp => $_, "$_.old"];
}

run map { ($_, '&') } [at] cmds;

This is also safer than system STRING in the case where your filenames
have funny characters in them.

> }
> print "End of excercise\n";
> exit;

Falling off the end is a perfectly valid way to end a Perl program. exit
is usually reserved for exceptional circumstances.

> I mean if this were a shell program - this would work:
>
> for x in `ls *.txt`
> do
> print "Copying $_ \n"
> cp $_ $_.old &
> done
> wait

This works because the shell implements '&' directly, rather than using
a different shell, so it can remember the pids to wait for itself.

Ben
Ben Morrow [ Mo, 14 Januar 2008 04:51 ] [ ID #1907729 ]

Re: Wait for background processes to complete

On Jan 13, 9:51 pm, Ben Morrow <b... [at] morrow.me.uk> wrote:
> Quoth pgodfrin <pgodf... [at] gmail.com>:
>
>
>
> > Here's what I want to do - run several commands in the background and
> > have the perl program wait for the commands to complete. Fork doesn't
> > do it, nor does wait nor waitpid.
>
> > Any thoughts?
>
> > Here's a sample program which starts the processes:
>
> > while (<*.txt>)
> > {
> > print "Copying $_ \n";
> > system("cp $_ $_.old &") ;
>
> This string contains a shell metachar (&), so system will fork a shell
> and wait for it. The shell will run cp in the background, and then exit,
> at which point system will return. Unfortunately, the only process which
> knew cp's pid was the shell, which has just exitted, so you can't wait
> for that process at all (cp now has init as its parent, like any other
> orphaned process).
>
> You need to either implement the behaviour you want with fork, exec and
> waitpid (it's a little complicated, but entirely possible) or use
> IPC::Run, something like
>
> use IPC::Run qw/run/;
>
> my [at] cmds;
>
> while (<*.txt>) {
> print "Copying $_\n";
> push [at] cmds, [cp => $_, "$_.old"];
> }
>
> run map { ($_, '&') } [at] cmds;
>
> This is also safer than system STRING in the case where your filenames
> have funny characters in them.
>
> > }
> > print "End of excercise\n";
> > exit;
>
> Falling off the end is a perfectly valid way to end a Perl program. exit
> is usually reserved for exceptional circumstances.
>
> > I mean if this were a shell program - this would work:
>
> > for x in `ls *.txt`
> > do
> > print "Copying $_ \n"
> > cp $_ $_.old &
> > done
> > wait
>
> This works because the shell implements '&' directly, rather than using
> a different shell, so it can remember the pids to wait for itself.
>
> Ben

OK - would you have a good example of the fork-system-waitpid method -
not the same one that's in all the other posts or the camel book?

smiles,
pg
pgodfrin [ Mo, 14 Januar 2008 06:10 ] [ ID #1907730 ]

Re: Wait for background processes to complete

On Jan 13, 9:43 pm, xhos... [at] gmail.com wrote:
> pgodfrin <pgodf... [at] gmail.com> wrote:
> > Greetings,
> > Well - I've spent a bunch of time trying to figure this out - to no
> > avail.
>
> > Here's what I want to do - run several commands in the background and
> > have the perl program wait for the commands to complete. Fork doesn't
> > do it, nor does wait nor waitpid.
>
> None of them individually do it, no. You have to use them together.
>
>
>
> > Any thoughts?
>
> > Here's a sample program which starts the processes:
>
> > while (<*.txt>)
> > {
> > print "Copying $_ \n";
> > system("cp $_ $_.old &") ;
>
> This starts a shell, which then starts cp in the background. As soon as
> the cp is *started*, the shell exits. So Perl has nothing to wait for, as
> the shell is already done (and waited for) before system returns. You need
> to use fork and system or fork and exec. Or you could use
> Parallel::ForkManager, which will wrap this stuff up nicely for you and
> also prevent you from fork-bombing your computer if there are thousands of
> *.txt
>
> > }
> > print "End of excercise\n";
> > exit;
>
> 1 until -1==wait(); # on my system, yours may differ
>
> Xho
>
> --
> --------------------http://NewsReader.Com/------------------ --
> The costs of publication of this article were defrayed in part by the
> payment of page charges. This article must therefore be hereby marked
> advertisement in accordance with 18 U.S.C. Section 1734 solely to indicate
> this fact.

Well - that's beginning to make a little sense - the shell completes
and perl has nothing to wait for. No wonder I'm pulling out what
little of my hair is left! :) I guess the fork process returns the pid
of the process, but - if it's the pid of the shell process, then we're
back to square one.
pgodfrin [ Mo, 14 Januar 2008 06:10 ] [ ID #1907731 ]

Re: Wait for background processes to complete

[please trim your quotations]

Quoth pgodfrin <pgodfrin [at] gmail.com>:
> On Jan 13, 9:51 pm, Ben Morrow <b... [at] morrow.me.uk> wrote:
> > Quoth pgodfrin <pgodf... [at] gmail.com>:
> >
> > > Here's what I want to do - run several commands in the background and
> > > have the perl program wait for the commands to complete. Fork doesn't
> > > do it, nor does wait nor waitpid.
> >
<snip>
> >
> > You need to either implement the behaviour you want with fork, exec and
> > waitpid (it's a little complicated, but entirely possible) or use
> > IPC::Run, something like
>
> OK - would you have a good example of the fork-system-waitpid method -
> not the same one that's in all the other posts or the camel book?

It's a more efficient use of everybody's time for you to use IPC::Run,
which has been written and tested by someone who understands these
issues and is prepared to solve them properly and portably, than it is
for a random Usenaut to provide you with a code snippet.

However, off the top of my head, completely untested, probably not
portable to Win32 or other non-POSIX systems, etc. etc.,

use POSIX qw/WNOHANG/;

{
my %kids;

$SIG{CHLD} = sub {
my ($pid, [at] died);
push [at] died, $pid while $pid = waitpid -1, WNOHANG;
delete [at] kids{ [at] died};
};

sub background {
my ( [at] cmd) = [at] _;

defined (my $pid = fork)
or die "can't fork for '$cmd[0]': $!";

if ($pid) {
$kids{$pid} = 1;
return;
}
else {
local $" = "' '";
exec [at] cmd or die "can't exec ' [at] cmd': $!";
}
}

sub finish {
waitpid $_, 0 for keys %kids;
%kids = ();
}
}

while (<*.txt>) {
print "Copying $_\n";
background cp => $_, "$_.old";
}

finish;

This will break if used in conjunction with system or anything else that
relies on SIGCHLD, and an OO person would probably say it should be
implemented as an object. Use IPC::Run.

Ben
Ben Morrow [ Mo, 14 Januar 2008 07:09 ] [ ID #1907732 ]

Re: Wait for background processes to complete

On Jan 13, 9:43 pm, xhos... [at] gmail.com wrote:
> pgodfrin <pgodf... [at] gmail.com> wrote:
> > Greetings,
> > Well - I've spent a bunch of time trying to figure this out - to no
> > avail.
>
> > Here's what I want to do - run several commands in the background and
> > have the perl program wait for the commands to complete. Fork doesn't
> > do it, nor does wait nor waitpid.
>
> None of them individually do it, no. You have to use them together.
>
>
>
> > Any thoughts?
>
> > Here's a sample program which starts the processes:
>
> > while (<*.txt>)
> > {
> > print "Copying $_ \n";
> > system("cp $_ $_.old &") ;
>
> This starts a shell, which then starts cp in the background. As soon as
> the cp is *started*, the shell exits. So Perl has nothing to wait for, as
> the shell is already done (and waited for) before system returns. You need
> to use fork and system or fork and exec. Or you could use
> Parallel::ForkManager, which will wrap this stuff up nicely for you and
> also prevent you from fork-bombing your computer if there are thousands of
> *.txt
>
> > }
> > print "End of excercise\n";
> > exit;
>
> 1 until -1==wait(); # on my system, yours may differ
>
> Xho
>
> --
> --------------------http://NewsReader.Com/------------------ --
> The costs of publication of this article were defrayed in part by the
> payment of page charges. This article must therefore be hereby marked
> advertisement in accordance with 18 U.S.C. Section 1734 solely to indicate
> this fact.

Hi Xho,
Well - It seems you're on to something. Thanks. I have tested this
using system and fork (also exec) and it appears to be exactly what
you're saying - the pid returned by fork is not the pid of the cp
command.

Frankly I'm amazed that something as basic as this, handled easily by
a plain old shell, is not an easy thing in Perl. (no I don't want to
use a shell script for this - I'm a perl bigot :) ).

I'll take a look at Parallel::ForkManager and any other modules that
might be useful...

cheers,
pg
pgodfrin [ Mo, 14 Januar 2008 16:37 ] [ ID #1907749 ]

Re: Wait for background processes to complete

pgodfrin <pgodfrin [at] gmail.com> wrote:
> On Jan 13, 9:43 pm, xhos... [at] gmail.com wrote:
> > pgodfrin <pgodf... [at] gmail.com> wrote:
> > > Greetings,
> > > Well - I've spent a bunch of time trying to figure this out - to no
> > > avail.
> >
> > > Here's what I want to do - run several commands in the background and
> > > have the perl program wait for the commands to complete. Fork doesn't
> > > do it, nor does wait nor waitpid.
> >
> > None of them individually do it, no. You have to use them together.
> >
> >
> >
> > > Any thoughts?
> >
> > > Here's a sample program which starts the processes:
> >
> > > while (<*.txt>)
> > > {
> > > print "Copying $_ \n";
> > > system("cp $_ $_.old &") ;
> >
> > This starts a shell, which then starts cp in the background. As soon
> > as the cp is *started*, the shell exits. So Perl has nothing to wait
> > for, as the shell is already done (and waited for) before system
> > returns. You need to use fork and system or fork and exec. Or you
> > could use Parallel::ForkManager, which will wrap this stuff up nicely
> > for you and also prevent you from fork-bombing your computer if there
> > are thousands of *.txt
> >
> > > }
> > > print "End of excercise\n";
> > > exit;
> >
> > 1 until -1==wait(); # on my system, yours may differ
> >
>
> Well - that's beginning to make a little sense - the shell completes
> and perl has nothing to wait for. No wonder I'm pulling out what
> little of my hair is left! :) I guess the fork process returns the pid
> of the process, but - if it's the pid of the shell process, then we're
> back to square one.

The fork returns (to the parent) the pid of the process forked off.
(but you don't actually need to know the pid if you merely want to wait,
rather than waitpid.) If that forked-off process then itself starts the cp
in the background, of course you are no better off. But if the forked-off
process either becomes cp (using exec) or it starts up cp in the foreground
(using system without a "&"), then you now have something to wait for. In
the first case, you wait for cp itself. In the second case, you wait for
the forked-off perl process which is itself waiting for the cp.

$ perl -wle 'use strict; fork or exec "sleep " . $_*3 foreach 1..3 ; \
my $x; do {$x=wait; print $x} until $x==-1'
438
439
440
-1

Xho

--
-------------------- http://NewsReader.Com/ --------------------
The costs of publication of this article were defrayed in part by the
payment of page charges. This article must therefore be hereby marked
advertisement in accordance with 18 U.S.C. Section 1734 solely to indicate
this fact.
xhoster [ Mo, 14 Januar 2008 18:11 ] [ ID #1907752 ]

Re: Wait for background processes to complete

On Jan 14, 11:11 am, xhos... [at] gmail.com wrote:
> pgodfrin <pgodf... [at] gmail.com> wrote:
> > On Jan 13, 9:43 pm, xhos... [at] gmail.com wrote:
> > > pgodfrin <pgodf... [at] gmail.com> wrote:
> > > > Greetings,
> > > > Well - I've spent a bunch of time trying to figure this out - to no
> > > > avail.
>
> > > > Here's what I want to do - run several commands in the background and
> > > > have the perl program wait for the commands to complete. Fork doesn't
> > > > do it, nor does wait nor waitpid.
>
> > > None of them individually do it, no. You have to use them together.
>
> > > > Any thoughts?
>
> > > > Here's a sample program which starts the processes:
>
> > > > while (<*.txt>)
> > > > {
> > > > print "Copying $_ \n";
> > > > system("cp $_ $_.old &") ;
>
> > > This starts a shell, which then starts cp in the background. As soon
> > > as the cp is *started*, the shell exits. So Perl has nothing to wait
> > > for, as the shell is already done (and waited for) before system
> > > returns. You need to use fork and system or fork and exec. Or you
> > > could use Parallel::ForkManager, which will wrap this stuff up nicely
> > > for you and also prevent you from fork-bombing your computer if there
> > > are thousands of *.txt
>
> > > > }
> > > > print "End of excercise\n";
> > > > exit;
>
> > > 1 until -1==wait(); # on my system, yours may differ
>
> > Well - that's beginning to make a little sense - the shell completes
> > and perl has nothing to wait for. No wonder I'm pulling out what
> > little of my hair is left! :) I guess the fork process returns the pid
> > of the process, but - if it's the pid of the shell process, then we're
> > back to square one.
>
> The fork returns (to the parent) the pid of the process forked off.
> (but you don't actually need to know the pid if you merely want to wait,
> rather than waitpid.) If that forked-off process then itself starts the cp
> in the background, of course you are no better off. But if the forked-off
> process either becomes cp (using exec) or it starts up cp in the foreground
> (using system without a "&"), then you now have something to wait for. In
> the first case, you wait for cp itself. In the second case, you wait for
> the forked-off perl process which is itself waiting for the cp.
>
> $ perl -wle 'use strict; fork or exec "sleep " . $_*3 foreach 1..3 ; \
> my $x; do {$x=wait; print $x} until $x==-1'
> 438
> 439
> 440
> -1
>
> Xho
>
> --
> --------------------http://NewsReader.Com/------------------ --
> The costs of publication of this article were defrayed in part by the
> payment of page charges. This article must therefore be hereby marked
> advertisement in accordance with 18 U.S.C. Section 1734 solely to indicate
> this fact.

Hi Xho,
Well - your code and concepts work fine when you want to wait
sequentially. My goal here is to fire off x number of process and then
wait for ALL of them to complete (this is basically rudimentary job
control, trying to use the shell concepts and maximize parallelism).
So, that requires the use of the & to send a process to the
background. It looks like exec doesn't recognize the &, which leaves
the system() command - which leaves us back at square one. The shell
completes and the program has nothing to wait for.

What's interesting is by using the system(" ... &") construct, the
background tasks all get the same PGID, which makes me wonder if
waitpid(0, <flags> ) should wait for wait for process in the process
group of the main perl program...

I wonder...

smiles,
pg
pgodfrin [ Mo, 14 Januar 2008 20:05 ] [ ID #1907764 ]

Re: Wait for background processes to complete

pgodfrin <pgodfrin [at] gmail.com> wrote:
> On Jan 14, 11:11 am, xhos... [at] gmail.com wrote:
> >
> > The fork returns (to the parent) the pid of the process forked off.
> > (but you don't actually need to know the pid if you merely want to
> > wait, rather than waitpid.) If that forked-off process then itself
> > starts the cp in the background, of course you are no better off. But
> > if the forked-off process either becomes cp (using exec) or it starts
> > up cp in the foreground (using system without a "&"), then you now have
> > something to wait for. In the first case, you wait for cp itself. In
> > the second case, you wait for the forked-off perl process which is
> > itself waiting for the cp.
> >
> > $ perl -wle 'use strict; fork or exec "sleep " . $_*3 foreach 1..3 ; \
> > my $x; do {$x=wait; print $x} until $x==-1'
> > 438
> > 439
> > 440
> > -1
> >
>
> Hi Xho,
> Well - your code and concepts work fine when you want to wait
> sequentially.

Is there an alternative to waiting sequentially? Waiting sequentially
is what the shell does, too, behind the scenes.

> My goal here is to fire off x number of process and then
> wait for ALL of them to complete

That is what my code does.

> (this is basically rudimentary job
> control, trying to use the shell concepts and maximize parallelism).
> So, that requires the use of the & to send a process to the
> background.

No, that is not required. Since Perl is not a shell, there really
isn't such a thing as the "background" in a Perl context. However,
fork will launch another process which runs without blocking the original
process (well, at least not until the original process asks to be blocked)
or blocking sibling processes. That is what you want, no?

> It looks like exec doesn't recognize the &, which leaves
> the system() command - which leaves us back at square one. The shell
> completes and the program has nothing to wait for.

Yes, so don't do that. "&" basically means "Fork and then don't wait".
Since that isn't what you want to do, then don't do that. Do your own
fork, and then do your own wait.

Xho

--
-------------------- http://NewsReader.Com/ --------------------
The costs of publication of this article were defrayed in part by the
payment of page charges. This article must therefore be hereby marked
advertisement in accordance with 18 U.S.C. Section 1734 solely to indicate
this fact.
xhoster [ Mo, 14 Januar 2008 21:48 ] [ ID #1907774 ]

Re: Wait for background processes to complete

On Jan 13, 7:08 pm, pgodfrin <pgodf... [at] gmail.com> wrote:
> Greetings,
> Well - I've spent a bunch of time trying to figure this out - to no
> avail.
>
> Here's what I want to do - run several commands in the background and
> have the perl program wait for the commands to complete. Fork doesn't
> do it, nor does wait nor waitpid.
>
> Any thoughts?
>
> Here's a sample program which starts the processes:
>
> while (<*.txt>)
> {
> print "Copying $_ \n";
> system("cp $_ $_.old &") ;
> }
> print "End of excercise\n";
> exit;
>
> I mean if this were a shell program - this would work:
>
> for x in `ls *.txt`
> do
> print "Copying $_ \n"
> cp $_ $_.old &
> done
> wait
>

A 'quick 'n dirty' take :)

while (<*.txt>) {
...
system("cp $_ $_.old &") ;
}
my $jobs;
do { sleep 1; $jobs =`ps |grep cp`; }
while $jobs;


--
Charles DeRykus
Charles DeRykus [ Mo, 14 Januar 2008 23:26 ] [ ID #1907781 ]

Re: Wait for background processes to complete

On Jan 14, 2:48 pm, xhos... [at] gmail.com wrote:
> pgodfrin <pgodf... [at] gmail.com> wrote:
> > On Jan 14, 11:11 am, xhos... [at] gmail.com wrote:
>
> > > The fork returns (to the parent) the pid of the process forked off.
> > > (but you don't actually need to know the pid if you merely want to
> > > wait, rather than waitpid.) If that forked-off process then itself
> > > starts the cp in the background, of course you are no better off. But
> > > if the forked-off process either becomes cp (using exec) or it starts
> > > up cp in the foreground (using system without a "&"), then you now have
> > > something to wait for. In the first case, you wait for cp itself. In
> > > the second case, you wait for the forked-off perl process which is
> > > itself waiting for the cp.
>
> > > $ perl -wle 'use strict; fork or exec "sleep " . $_*3 foreach 1..3 ; \
> > > my $x; do {$x=wait; print $x} until $x==-1'
> > > 438
> > > 439
> > > 440
> > > -1
>
> > Hi Xho,
> > Well - your code and concepts work fine when you want to wait
> > sequentially.
>
> Is there an alternative to waiting sequentially? Waiting sequentially
> is what the shell does, too, behind the scenes.
>
> > My goal here is to fire off x number of process and then
> > wait for ALL of them to complete
>
> That is what my code does.
>
> > (this is basically rudimentary job
> > control, trying to use the shell concepts and maximize parallelism).
> > So, that requires the use of the & to send a process to the
> > background.
>
> No, that is not required. Since Perl is not a shell, there really
> isn't such a thing as the "background" in a Perl context. However,
> fork will launch another process which runs without blocking the original
> process (well, at least not until the original process asks to be blocked)
> or blocking sibling processes. That is what you want, no?
>
> > It looks like exec doesn't recognize the &, which leaves
> > the system() command - which leaves us back at square one. The shell
> > completes and the program has nothing to wait for.
>
> Yes, so don't do that. "&" basically means "Fork and then don't wait".
> Since that isn't what you want to do, then don't do that. Do your own
> fork, and then do your own wait.
>
> Xho
>
> --
> --------------------http://NewsReader.Com/------------------ --
> The costs of publication of this article were defrayed in part by the
> payment of page charges. This article must therefore be hereby marked
> advertisement in accordance with 18 U.S.C. Section 1734 solely to indicate
> this fact.

Hi Xho,
It seems to me that firing off say 5 processes with the '&' character
to send them to the background is 5 parallel processes, while
executing them off one at a time is sequential. Your code (fork or
exec "sleep" ... ) waits for each sleep process to complete - so that
is what I meant by "waiting sequentially". Technically speaking you're
right - but the idea is to have tasks run in parallel versus
sequentially, which is ostensibly faster.

Insofar as using fork() - your original observation still stands -
system() runs a shell command and then terminates after sending the
command within to run (I watched two different PIDs - the long running
command within the system() statement continued while the shell became
<defunct>)

To make a long story short, this is how I solved the problem. It seems
that the PIDs of the commands run via system() and the '&' background
thing end up belonging to the same Process Group - seen in the ps
command, plus a little extra:

ps -C cp -o pid,pgid,command
PID PGID COMMAND
29068 29063 cp example01.txt example01.txt.old
29070 29063 cp example02.txt example02.txt.old
29072 29063 cp example03.txt example03.txt.old
29074 29063 cp example04.txt example04.txt.old
29076 29063 cp example05.txt example05.txt.old
29078 29063 cp example06.txt example06.txt.old

So I wrap the ps command and do some looping:

for (;;)
{
open PGRP, "ps -C cp h |" ;
[at] pidlist=<PGRP> ;
if ($#pidlist<0) {die "\nNo more processes\n" ;}
}

It's not pretty but it works...

But, I believe this is an architectural FLAW with Perl.

regards,
pg
pgodfrin [ Di, 15 Januar 2008 23:04 ] [ ID #1908814 ]

Re: Wait for background processes to complete

pgodfrin wrote:
[...]
> So I wrap the ps command and do some looping:
>
> for (;;)
> {
> open PGRP, "ps -C cp h |" ;
> [at] pidlist=<PGRP> ;
> if ($#pidlist<0) {die "\nNo more processes\n" ;}
> }
>
> It's not pretty but it works...

Why not use Parallel::ForkManager? It IS pretty and will
use much less system resources, compared to running many
'ps' commands.


> But, I believe this is an architectural FLAW with Perl.

Everyone else believes it's due to your level of knowledge.
glex_no-spam [ Di, 15 Januar 2008 23:16 ] [ ID #1908816 ]

Re: Wait for background processes to complete

Quoth pgodfrin <pgodfrin [at] gmail.com>:
> On Jan 14, 2:48 pm, xhos... [at] gmail.com wrote:
> > pgodfrin <pgodf... [at] gmail.com> wrote:
> > > On Jan 14, 11:11 am, xhos... [at] gmail.com wrote:
> >
> > > > $ perl -wle 'use strict; fork or exec "sleep " . $_*3 foreach 1..3 ; \
> > > > my $x; do {$x=wait; print $x} until $x==-1'

<snippage>

> It seems to me that firing off say 5 processes with the '&' character
> to send them to the background is 5 parallel processes, while
> executing them off one at a time is sequential. Your code (fork or
> exec "sleep" ... ) waits for each sleep process to complete - so that
> is what I meant by "waiting sequentially".

No, I think you don't understand how fork works. It *is* rather
confusing until you're used to it. Read the documentation again (both
Perl's and your system's), or find a good Unix programming book.

> Technically speaking you're
> right - but the idea is to have tasks run in parallel versus
> sequentially, which is ostensibly faster.

The tasks do run in parallel with Xho's version.

> To make a long story short, this is how I solved the problem. It seems
> that the PIDs of the commands run via system() and the '&' background
> thing end up belonging to the same Process Group - seen in the ps
> command, plus a little extra:
>
<snip>
> So I wrap the ps command and do some looping:
>
> for (;;)
> {
> open PGRP, "ps -C cp h |" ;

Use lexical filehandles and three-or-more-arg open.
Check the return value.

open my $PGRP, '-|', 'ps', '-C', 'cp', 'h'
or die "couldn't fork ps: $!";

> [at] pidlist=<PGRP> ;
> if ($#pidlist<0) {die "\nNo more processes\n" ;}

IMHO any use of $#ary is an error; certainly in this case you should be
using [at] pidlist instead.

[at] pidlist or die "No more processes\n";

This will run around in a tight loop running probably hundreds of ps
processes per second. This is not a effective use of your system's
resources, to say the least. If you must poll like this you need a sleep
in there somewhere to limit the damage.

> }
>
> It's not pretty but it works...

Yuck. The whole point of the wait syscall is to avoid nastiness like
that. I suggest you learn how it works, or use a module written by
someone who does (you have been given at least two suggestions so far),
or stick to shell.

> But, I believe this is an architectural FLAW with Perl.

No. Firstly, the only flaw here is in your understanding; secondly, if
there was a flaw it would be in Unix, not Perl, since Perl just exposes
the underlying system interfaces.

Ben
Ben Morrow [ Mi, 16 Januar 2008 00:49 ] [ ID #1908825 ]

Re: Wait for background processes to complete

On Jan 14, 2:05=A0pm, pgodfrin <pgodf... [at] gmail.com> wrote:
> On Jan 14, 11:11 am, xhos... [at] gmail.com wrote:
>
>
>
> > pgodfrin <pgodf... [at] gmail.com> wrote:
> > > On Jan 13, 9:43 pm, xhos... [at] gmail.com wrote:
> > > > pgodfrin <pgodf... [at] gmail.com> wrote:
> > > > > Greetings,
> > > > > Well - I've spent a bunch of time trying to figure this out - to n=
o
> > > > > avail.
>
> > > > > Here's what I want to do - run several commands in the background =
and
> > > > > have the perl program wait for the commands to complete. Fork does=
n't
> > > > > do it, nor does wait nor waitpid.
>
> > > > None of them individually do it, no. =A0You have to use them togethe=
r.
>
> > > > > Any thoughts?
>
> > > > > Here's a sample program which starts the processes:
>
> > > > > =A0 =A0while (<*.txt>)
> > > > > =A0 =A0{
> > > > > =A0 =A0 =A0 =A0 print "Copying =A0$_ \n";
> > > > > =A0 =A0 =A0 =A0 system("cp $_ $_.old &") ;
>
> > > > This starts a shell, which then starts cp in the background. =A0As s=
oon
> > > > as the cp is *started*, the shell exits. =A0So Perl has nothing to w=
ait
> > > > for, as the shell is already done (and waited for) before system
> > > > returns. =A0You need to use fork and system or fork and exec. Or you=

> > > > could use Parallel::ForkManager, which will wrap this stuff up nicel=
y
> > > > for you and also prevent you from fork-bombing your computer if ther=
e
> > > > are thousands of *.txt
>
> > > > > =A0 =A0}
> > > > > =A0 =A0print "End of excercise\n";
> > > > > =A0 =A0exit;
>
> > > > 1 until -1=3D=3Dwait(); =A0# on my system, yours may differ
>
> > > Well - that's beginning to make a little sense - the shell completes
> > > and perl has nothing to wait for. No wonder I'm pulling out what
> > > little of my hair is left! :) I guess the fork process returns the pid=

> > > of the process, but - if it's the pid of the shell process, then we're=

> > > back to square one.
>
> > The fork returns (to the parent) the pid of the process forked off.
> > (but you don't actually need to know the pid if you merely want to wait,=

> > rather than waitpid.) =A0If that forked-off process then itself starts t=
he cp
> > in the background, of course you are no better off. =A0But if the forked=
-off
> > process either becomes cp (using exec) or it starts up cp in the foregro=
und
> > (using system without a "&"), then you now have something to wait for. =
=A0In
> > the first case, you wait for cp itself. =A0In the second case, you wait =
for
> > the forked-off perl process which is itself waiting for the cp.
>
> > $ perl -wle 'use strict; fork or exec "sleep " . $_*3 foreach 1..3 ; \
> > =A0 =A0 =A0 =A0 =A0 =A0 =A0 my $x; do {$x=3Dwait; print $x} until $x=3D=
=3D-1'
> > 438
> > 439
> > 440
> > -1
>
> > Xho
>
> > --
> > --------------------http://NewsReader.Com/------------------ --
> > The costs of publication of this article were defrayed in part by the
> > payment of page charges. This article must therefore be hereby marked
> > advertisement in accordance with 18 U.S.C. Section 1734 solely to indica=
te
> > this fact.
>
> Hi Xho,
> Well - your code and concepts work fine when you want to wait
> sequentially. My goal here is to fire off x number of process and then
> wait for ALL of them to complete (this is basically rudimentary job
> control, trying to use the shell concepts and maximize parallelism).

Reading Xho's code, it looks like 3 processes are kicked off. 1 sleeps
3 seconds, 2 sleeps 6 seconds, and 3 sleeps 9 seconds.
If the processes were sequential, you wouldn't see the last pid until
after 18 seconds. instead you see it after 9 seconds.

HTH
it_says_BALLS_on_your [ Mi, 16 Januar 2008 16:17 ] [ ID #1909998 ]

Re: Wait for background processes to complete

On Jan 15, 5:49 pm, Ben Morrow <b... [at] morrow.me.uk> wrote:

>
> <snip>
> > So I wrap the ps command and do some looping:
>
> > for (;;)
> > {
> > open PGRP, "ps -C cp h |" ;
>
> Use lexical filehandles and three-or-more-arg open.
> Check the return value.
>
> open my $PGRP, '-|', 'ps', '-C', 'cp', 'h'
> or die "couldn't fork ps: $!";
>
> > [at] pidlist=<PGRP> ;
> > if ($#pidlist<0) {die "\nNo more processes\n" ;}
>
> IMHO any use of $#ary is an error; certainly in this case you should be
> using [at] pidlist instead.
>
> [at] pidlist or die "No more processes\n";
>
> This will run around in a tight loop running probably hundreds of ps
> processes per second. This is not a effective use of your system's
> resources, to say the least. If you must poll like this you need a sleep
> in there somewhere to limit the damage.
>
> > }
>
> > It's not pretty but it works...
>
> Yuck. The whole point of the wait syscall is to avoid nastiness like
> that. I suggest you learn how it works, or use a module written by
> someone who does (you have been given at least two suggestions so far),
> or stick to shell.
>
> > But, I believe this is an architectural FLAW with Perl.
>
> No. Firstly, the only flaw here is in your understanding; secondly, if
> there was a flaw it would be in Unix, not Perl, since Perl just exposes
> the underlying system interfaces.
>
> Ben



Whew! I knew I might get some feather's ruffled with the 'flaw'
comment. Sorry my knowledge is not as extensive as yours
(collectively) - but it appears it is true.

I had an exit statement in the if..elsif construct. By removing that
exit and changing the system() to exec() I am at least getting the
fork() process to kick off multiple tasks.

I'm still having problems making it wait though. I think I'm getting
there. I'll report back later - when my knowledge has increased :)
pg
(sorry Xho...)
pgodfrin [ Mi, 16 Januar 2008 19:19 ] [ ID #1910009 ]

Re: Wait for background processes to complete

On Jan 15, 5:49 pm, Ben Morrow <b... [at] morrow.me.uk> wrote:
> Quoth pgodfrin <pgodf... [at] gmail.com>:
>
> > On Jan 14, 2:48 pm, xhos... [at] gmail.com wrote:
> > > pgodfrin <pgodf... [at] gmail.com> wrote:
> > > > On Jan 14, 11:11 am, xhos... [at] gmail.com wrote:
>
> > > > > $ perl -wle 'use strict; fork or exec "sleep " . $_*3 foreach 1..3 ; \
> > > > > my $x; do {$x=wait; print $x} until $x==-1'
>
> <snippage>
>
> > It seems to me that firing off say 5 processes with the '&' character
> > to send them to the background is 5 parallel processes, while
> > executing them off one at a time is sequential. Your code (fork or
> > exec "sleep" ... ) waits for each sleep process to complete - so that
> > is what I meant by "waiting sequentially".
>
> No, I think you don't understand how fork works. It *is* rather
> confusing until you're used to it. Read the documentation again (both
> Perl's and your system's), or find a good Unix programming book.
>
> > Technically speaking you're
> > right - but the idea is to have tasks run in parallel versus
> > sequentially, which is ostensibly faster.
>
> The tasks do run in parallel with Xho's version.
>
>
>
> > To make a long story short, this is how I solved the problem. It seems
> > that the PIDs of the commands run via system() and the '&' background
> > thing end up belonging to the same Process Group - seen in the ps
> > command, plus a little extra:
>
> <snip>
> > So I wrap the ps command and do some looping:
>
> > for (;;)
> > {
> > open PGRP, "ps -C cp h |" ;
>
> Use lexical filehandles and three-or-more-arg open.
> Check the return value.
>
> open my $PGRP, '-|', 'ps', '-C', 'cp', 'h'
> or die "couldn't fork ps: $!";
>
> > [at] pidlist=<PGRP> ;
> > if ($#pidlist<0) {die "\nNo more processes\n" ;}
>
> IMHO any use of $#ary is an error; certainly in this case you should be
> using [at] pidlist instead.
>
> [at] pidlist or die "No more processes\n";
>
> This will run around in a tight loop running probably hundreds of ps
> processes per second. This is not a effective use of your system's
> resources, to say the least. If you must poll like this you need a sleep
> in there somewhere to limit the damage.
>
> > }
>
> > It's not pretty but it works...
>
> Yuck. The whole point of the wait syscall is to avoid nastiness like
> that. I suggest you learn how it works, or use a module written by
> someone who does (you have been given at least two suggestions so far),
> or stick to shell.
>
> > But, I believe this is an architectural FLAW with Perl.
>
> No. Firstly, the only flaw here is in your understanding; secondly, if
> there was a flaw it would be in Unix, not Perl, since Perl just exposes
> the underlying system interfaces.
>
> Ben
darn... still can't make it wait!
pg
pgodfrin [ Mi, 16 Januar 2008 22:00 ] [ ID #1910023 ]

Re: Wait for background processes to complete

Hi Ben,
Well - it seems I have made some progress.But - I still need some
advice...

Here's my code:

#!/usr/bin/perl
use POSIX ":sys_wait_h";
$SIG{CHLD} = sub { wait }; # an 'installed' signal handler

$f=0 ;
while (</fausb/sample/*.txt>)
{
$f += 1;
if ($pid = fork)
{
print "Fork $f pid: $pid\n" ;
print "Copying $_ ($pid)\n";
# exec() NEVER returns...
exec("cp $_ $_.old") ;
} elsif (defined $pid)
{
print "Found child...($pid)\n" ;
} elsif ($! =~ /No more process/)
{
print "Fork returned no more processes\n";
} else
{
die "Fork error.\n";
} # end fork
} # end while
print "\n<<<<< End of exercise >>>>>\n";
exit;

So - this code ends up starting 6 forks, and then falls out of the
while(<*.txt>) loop - printing the 'End of exercise' message. A 'ps -
ef |grep fk' (fktest5 is the name of this program) shows it's no
longer running, but the cp command indeed are still running.

What I would like to do is wait for the cp processes to finish before
executing the exit statement.

Any ideas?

thanks,
pg
pgodfrin [ Mi, 16 Januar 2008 22:46 ] [ ID #1910025 ]

Re: Wait for background processes to complete

pgodfrin <pgodfrin [at] gmail.com> wrote:
> Hi Ben,
> Well - it seems I have made some progress.But - I still need some
> advice...
>
> Here's my code:
>
> #!/usr/bin/perl
> use POSIX ":sys_wait_h";
> $SIG{CHLD} = sub { wait }; # an 'installed' signal handler

You probably don't need a signal handler. And if you want it,
you should aware that that signal can be fired even when there is
no child ready to be waited for, leading to blocking in the wait.
So you would probably want to do a nonblocking waitpid instead.

>
> $f=0 ;
> while (</fausb/sample/*.txt>)
> {
> $f += 1;
> if ($pid = fork)
> {
> print "Fork $f pid: $pid\n" ;
> print "Copying $_ ($pid)\n";
> # exec() NEVER returns...
> exec("cp $_ $_.old") ;
> } elsif (defined $pid)
> {
> print "Found child...($pid)\n" ;
> } elsif ($! =~ /No more process/)
> {
> print "Fork returned no more processes\n";
> } else
> {
> die "Fork error.\n";
> } # end fork
> } # end while
> print "\n<<<<< End of exercise >>>>>\n";

## On Linux, wait returns -1 when there are no living children to wait for.
1 until -1==wait();

> exit;

Xho

--
-------------------- http://NewsReader.Com/ --------------------
The costs of publication of this article were defrayed in part by the
payment of page charges. This article must therefore be hereby marked
advertisement in accordance with 18 U.S.C. Section 1734 solely to indicate
this fact.
xhoster [ Mi, 16 Januar 2008 23:17 ] [ ID #1910027 ]

Re: Wait for background processes to complete

On Jan 16, 4:17 pm, xhos... [at] gmail.com wrote:
> pgodfrin <pgodf... [at] gmail.com> wrote:
> > Hi Ben,
> > Well - it seems I have made some progress.But - I still need some
> > advice...
>
> > Here's my code:
>
> > #!/usr/bin/perl
> > use POSIX ":sys_wait_h";
> > $SIG{CHLD} = sub { wait }; # an 'installed' signal handler
>
> You probably don't need a signal handler. And if you want it,
> you should aware that that signal can be fired even when there is
> no child ready to be waited for, leading to blocking in the wait.
> So you would probably want to do a nonblocking waitpid instead.
>
>
>
>
>
> > $f=0 ;
> > while (</fausb/sample/*.txt>)
> > {
> > $f += 1;
> > if ($pid = fork)
> > {
> > print "Fork $f pid: $pid\n" ;
> > print "Copying $_ ($pid)\n";
> > # exec() NEVER returns...
> > exec("cp $_ $_.old") ;
> > } elsif (defined $pid)
> > {
> > print "Found child...($pid)\n" ;
> > } elsif ($! =~ /No more process/)
> > {
> > print "Fork returned no more processes\n";
> > } else
> > {
> > die "Fork error.\n";
> > } # end fork
> > } # end while
> > print "\n<<<<< End of exercise >>>>>\n";
>
> ## On Linux, wait returns -1 when there are no living children to wait for.
> 1 until -1==wait();
>
> > exit;
>
> Xho
>
> --
> --------------------http://NewsReader.Com/------------------ --
> The costs of publication of this article were defrayed in part by the
> payment of page charges. This article must therefore be hereby marked
> advertisement in accordance with 18 U.S.C. Section 1734 solely to indicate
> this fact.

Thanks Xho - I've removed the signal handler, but it seems wait always
returns -1 so - the loop is a nop? Where in the code should it go?

thanks,
pg
pgodfrin [ Mi, 16 Januar 2008 23:29 ] [ ID #1910028 ]

Re: Wait for background processes to complete

On Jan 16, 2:29 pm, pgodfrin <pgodf... [at] gmail.com> wrote:
> On Jan 16, 4:17 pm, xhos... [at] gmail.com wrote:
>
>
>
> > pgodfrin <pgodf... [at] gmail.com> wrote:
> > > Hi Ben,
> > > Well - it seems I have made some progress.But - I still need some
> > > advice...
>
> > > Here's my code:
>
> > > #!/usr/bin/perl
> > > use POSIX ":sys_wait_h";
> > > $SIG{CHLD} = sub { wait }; # an 'installed' signal handler
>
> > You probably don't need a signal handler. And if you want it,
> > you should aware that that signal can be fired even when there is
> > no child ready to be waited for, leading to blocking in the wait.
> > So you would probably want to do a nonblocking waitpid instead.
>
> > > $f=0 ;
> > > while (</fausb/sample/*.txt>)
> > > {
> > > $f += 1;
> > > if ($pid = fork)
> > > {
> > > print "Fork $f pid: $pid\n" ;
> > > print "Copying $_ ($pid)\n";
> > > # exec() NEVER returns...
> > > exec("cp $_ $_.old") ;
> > > } elsif (defined $pid)
> > > {
> > > print "Found child...($pid)\n" ;
> > > } elsif ($! =~ /No more process/)
> > > {
> > > print "Fork returned no more processes\n";
> > > } else
> > > {
> > > die "Fork error.\n";
> > > } # end fork
> > > } # end while
> > > print "\n<<<<< End of exercise >>>>>\n";
>
> > ## On Linux, wait returns -1 when there are no living children to wait for.
> > 1 until -1==wait();
>
> > > exit;
>

> Thanks Xho - I've removed the signal handler, but it seems wait always
> returns -1 so - the loop is a nop? Where in the code should it go?
>

I'll pipe in here since the 'quick 'n dirty' solution
was mangled and diss'ed.

The safest action is an asynchronous wait with a
tight loop in the handler (perldoc perlipc):

use POSIX ":sys_wait_h";
$SIG{CHLD} = \&REAPER;

# now do something that forks...
...

sub REAPER { 1 while waitpid(-1, WNOHANG)) > 0; }


--
Charles DeRykus
Charles DeRykus [ Do, 17 Januar 2008 01:52 ] [ ID #1910914 ]

Re: Wait for background processes to complete

On Jan 13, 10:09 pm, Ben Morrow <b... [at] morrow.me.uk> wrote:
> [please trim your quotations]
>
> Quoth pgodfrin <pgodf... [at] gmail.com>:
>
> > On Jan 13, 9:51 pm, Ben Morrow <b... [at] morrow.me.uk> wrote:
> > > Quoth pgodfrin <pgodf... [at] gmail.com>:
>
> > > > Here's what I want to do - run several commands in the background and
> > > > have the perl program wait for the commands to complete. Fork doesn't
> > > > do it, nor does wait nor waitpid.
>
> <snip>
>
> > > You need to either implement the behaviour you want with fork, exec and
> > > waitpid (it's a little complicated, but entirely possible) or use
> > > IPC::Run, something like
>
> > OK - would you have a good example of the fork-system-waitpid method -
> > not the same one that's in all the other posts or the camel book?
>
> It's a more efficient use of everybody's time for you to use IPC::Run,
> which has been written and tested by someone who understands these
> issues and is prepared to solve them properly and portably, than it is
> for a random Usenaut to provide you with a code snippet.
>
> However, off the top of my head, completely untested, probably not
> portable to Win32 or other non-POSIX systems, etc. etc.,
>
> use POSIX qw/WNOHANG/;
>
> {
> my %kids;
>
> $SIG{CHLD} = sub {
> my ($pid, [at] died);
> push [at] died, $pid while $pid = waitpid -1, WNOHANG;
> delete [at] kids{ [at] died};
> };
>
> sub background {
> my ( [at] cmd) = [at] _;
>
> defined (my $pid = fork)
> or die "can't fork for '$cmd[0]': $!";
>
> if ($pid) {
> $kids{$pid} = 1;
> return;
> }
> else {
> local $" = "' '";
> exec [at] cmd or die "can't exec ' [at] cmd': $!";
> }
> }
>
> sub finish {
> waitpid $_, 0 for keys %kids;
> %kids = ();
> }
> }
>
> while (<*.txt>) {
> print "Copying $_\n";
> background cp => $_, "$_.old";
> }
>
> finish;
>
> This will break if used in conjunction with system or anything else that
> relies on SIGCHLD, and an OO person would probably say it should be
> implemented as an object. Use IPC::Run.
>
> Ben

I really don't grasp the significance of having $kids{$pid} equal 1.
Can some enlighten me o this?
grocery_stocker [ Do, 17 Januar 2008 03:06 ] [ ID #1910916 ]

Re: Wait for background processes to complete

Quoth grocery_stocker <cdalten [at] gmail.com>:
> On Jan 13, 10:09 pm, Ben Morrow <b... [at] morrow.me.uk> wrote:
> >
<snip>
> > $SIG{CHLD} = sub {
> > my ($pid, [at] died);
> > push [at] died, $pid while $pid = waitpid -1, WNOHANG;
> > delete [at] kids{ [at] died};
> > };
<snip>
> > if ($pid) {
> > $kids{$pid} = 1;
> > return;
> > }
<snip>
> > sub finish {
> > waitpid $_, 0 for keys %kids;
> > %kids = ();
> > }
>
> I really don't grasp the significance of having $kids{$pid} equal 1.
> Can some enlighten me o this?

It's one of the standard idioms for using a hash as a set. Every time we
create a child, we add an entry to the hash; every time one dies on its
own, we delete its entry. Then at the end we can use keys %pids to
retrieve the list of pids we still need to wait for. The only thing that
matters about %kids are its keys: we never use the values, so they can
be set to anything. I prefer using 1 since then the values are all true;
you can get slightly better memory use with

$kids{$pid} = ();

which inserts the key but doesn't create a value for it at all, but then
you have to test with exists, which I find annoying. Since in this case
I don't test for existance of keys at all, this doesn't matter: using 1 is
just a habit.

Ben
Ben Morrow [ Do, 17 Januar 2008 06:37 ] [ ID #1910927 ]

Re: Wait for background processes to complete

On Jan 16, 6:52 pm, "comp.llang.perl.moderated" <c... [at] blv-
sam-01.ca.boeing.com> wrote:
> On Jan 16, 2:29 pm, pgodfrin <pgodf... [at] gmail.com> wrote:
>
>
>
> > On Jan 16, 4:17 pm, xhos... [at] gmail.com wrote:
>
> > > pgodfrin <pgodf... [at] gmail.com> wrote:
> > > > Hi Ben,
> > > > Well - it seems I have made some progress.But - I still need some
> > > > advice...
>
> > > > Here's my code:
>
> > > > #!/usr/bin/perl
> > > > use POSIX ":sys_wait_h";
> > > > $SIG{CHLD} = sub { wait }; # an 'installed' signal handler
>
> > > You probably don't need a signal handler. And if you want it,
> > > you should aware that that signal can be fired even when there is
> > > no child ready to be waited for, leading to blocking in the wait.
> > > So you would probably want to do a nonblocking waitpid instead.
>
> > > > $f=0 ;
> > > > while (</fausb/sample/*.txt>)
> > > > {
> > > > $f += 1;
> > > > if ($pid = fork)
> > > > {
> > > > print "Fork $f pid: $pid\n" ;
> > > > print "Copying $_ ($pid)\n";
> > > > # exec() NEVER returns...
> > > > exec("cp $_ $_.old") ;
> > > > } elsif (defined $pid)
> > > > {
> > > > print "Found child...($pid)\n" ;
> > > > } elsif ($! =~ /No more process/)
> > > > {
> > > > print "Fork returned no more processes\n";
> > > > } else
> > > > {
> > > > die "Fork error.\n";
> > > > } # end fork
> > > > } # end while
> > > > print "\n<<<<< End of exercise >>>>>\n";
>
> > > ## On Linux, wait returns -1 when there are no living children to wait for.
> > > 1 until -1==wait();
>
> > > > exit;
>
> > Thanks Xho - I've removed the signal handler, but it seems wait always
> > returns -1 so - the loop is a nop? Where in the code should it go?
>
> I'll pipe in here since the 'quick 'n dirty' solution
> was mangled and diss'ed.
>
> The safest action is an asynchronous wait with a
> tight loop in the handler (perldoc perlipc):
>
> use POSIX ":sys_wait_h";
> $SIG{CHLD} = \&REAPER;
>
> # now do something that forks...
> ...
>
> sub REAPER { 1 while waitpid(-1, WNOHANG)) > 0; }
>
> --
> Charles DeRykus

Hi Charles - still doesn't wait - in fact the REAPER subroutine never
even gets called - I'm beginning to get back the 'flaw' concept...

pg
pgodfrin [ Do, 17 Januar 2008 16:20 ] [ ID #1910944 ]

Re: Wait for background processes to complete

On Jan 17, 10:20=A0am, pgodfrin <pgodf... [at] gmail.com> wrote:
> On Jan 16, 6:52 pm, "comp.llang.perl.moderated" <c... [at] blv-
>
>
>
> sam-01.ca.boeing.com> wrote:
> > On Jan 16, 2:29 pm, pgodfrin <pgodf... [at] gmail.com> wrote:
>
> > > On Jan 16, 4:17 pm, xhos... [at] gmail.com wrote:
>
> > > > pgodfrin <pgodf... [at] gmail.com> wrote:
> > > > > Hi Ben,
> > > > > Well - it seems I have made some progress.But - I still need some
> > > > > advice...
>
> > > > > Here's my code:
>
> > > > > #!/usr/bin/perl
> > > > > use POSIX ":sys_wait_h";
> > > > > $SIG{CHLD} =3D sub { wait }; =A0# an 'installed' signal handler
>
> > > > You probably don't need a signal handler. =A0And if you want it,
> > > > you should aware that that signal can be fired even when there is
> > > > no child ready to be waited for, leading to blocking in the wait.
> > > > So you would probably want to do a nonblocking waitpid instead.
>
> > > > > $f=3D0 ;
> > > > > while (</fausb/sample/*.txt>)
> > > > > {
> > > > > =A0 =A0$f +=3D 1;
> > > > > =A0 =A0if ($pid =3D fork)
> > > > > =A0 =A0{
> > > > > =A0 =A0print "Fork $f pid: $pid\n" ;
> > > > > =A0 =A0print "Copying =A0$_ ($pid)\n";
> > > > > =A0 =A0# exec() NEVER returns...
> > > > > =A0 =A0exec("cp $_ $_.old") ;
> > > > > =A0 =A0} elsif (defined $pid)
> > > > > =A0 =A0{
> > > > > =A0 =A0 =A0 print "Found child...($pid)\n" ;
> > > > > =A0 =A0} elsif ($! =3D~ /No more process/)
> > > > > =A0 =A0{
> > > > > =A0 =A0 =A0 print "Fork returned no more processes\n";
> > > > > =A0 =A0} else
> > > > > =A0 =A0{
> > > > > =A0 =A0 =A0 die "Fork error.\n";
> > > > > =A0 =A0} =A0# end fork
> > > > > } =A0# end while
> > > > > print "\n<<<<< End of exercise >>>>>\n";
>
> > > > ## On Linux, wait returns -1 when there are no living children to wa=
it for.
> > > > 1 until -1=3D=3Dwait();
>
> > > > > exit;
>
> > > Thanks Xho - I've removed the signal handler, but it seems wait always=

> > > returns -1 so - the loop is a nop? Where in the code should it go?
>
> > I'll pipe in here since the 'quick 'n dirty' solution
> > was mangled and diss'ed.
>
> > The safest action is an asynchronous wait with a
> > tight loop in the handler =A0(perldoc perlipc):
>
> > =A0 =A0use POSIX ":sys_wait_h";
> > =A0 =A0$SIG{CHLD} =3D \&REAPER;
>
> > =A0 =A0# now do something that forks...
> > =A0 =A0...
>
> > =A0 =A0sub REAPER { 1 while waitpid(-1, WNOHANG)) > 0; }
>
> > --
> > Charles DeRykus
>
> Hi Charles - still doesn't wait - in fact the REAPER subroutine never
> even gets called - I'm beginning to get back the 'flaw' concept...
>

What's wrong with Xho's code earlier in the thread?

$ perl -wle 'use strict; fork or exec "sleep " . $_*3 foreach 1..3 ;
\
my $x; do {$x=3Dwait; print $x} until $x=3D=3D-1'
it_says_BALLS_on_your [ Do, 17 Januar 2008 16:24 ] [ ID #1910946 ]

Re: Wait for background processes to complete

On Jan 17, 9:24 am, nolo contendere <simon.c... [at] fmr.com> wrote:
> On Jan 17, 10:20 am, pgodfrin <pgodf... [at] gmail.com> wrote:
>
>
>
> > On Jan 16, 6:52 pm, "comp.llang.perl.moderated" <c... [at] blv-
>
> > sam-01.ca.boeing.com> wrote:
> > > On Jan 16, 2:29 pm, pgodfrin <pgodf... [at] gmail.com> wrote:
>
> > > > On Jan 16, 4:17 pm, xhos... [at] gmail.com wrote:
>
> > > > > pgodfrin <pgodf... [at] gmail.com> wrote:
> > > > > > Hi Ben,
> > > > > > Well - it seems I have made some progress.But - I still need some
> > > > > > advice...
>
> > > > > > Here's my code:
>
> > > > > > #!/usr/bin/perl
> > > > > > use POSIX ":sys_wait_h";
> > > > > > $SIG{CHLD} = sub { wait }; # an 'installed' signal handler
>
> > > > > You probably don't need a signal handler. And if you want it,
> > > > > you should aware that that signal can be fired even when there is
> > > > > no child ready to be waited for, leading to blocking in the wait.
> > > > > So you would probably want to do a nonblocking waitpid instead.
>
> > > > > > $f=0 ;
> > > > > > while (</fausb/sample/*.txt>)
> > > > > > {
> > > > > > $f += 1;
> > > > > > if ($pid = fork)
> > > > > > {
> > > > > > print "Fork $f pid: $pid\n" ;
> > > > > > print "Copying $_ ($pid)\n";
> > > > > > # exec() NEVER returns...
> > > > > > exec("cp $_ $_.old") ;
> > > > > > } elsif (defined $pid)
> > > > > > {
> > > > > > print "Found child...($pid)\n" ;
> > > > > > } elsif ($! =~ /No more process/)
> > > > > > {
> > > > > > print "Fork returned no more processes\n";
> > > > > > } else
> > > > > > {
> > > > > > die "Fork error.\n";
> > > > > > } # end fork
> > > > > > } # end while
> > > > > > print "\n<<<<< End of exercise >>>>>\n";
>
> > > > > ## On Linux, wait returns -1 when there are no living children to wait for.
> > > > > 1 until -1==wait();
>
> > > > > > exit;
>
> > > > Thanks Xho - I've removed the signal handler, but it seems wait always
> > > > returns -1 so - the loop is a nop? Where in the code should it go?
>
> > > I'll pipe in here since the 'quick 'n dirty' solution
> > > was mangled and diss'ed.
>
> > > The safest action is an asynchronous wait with a
> > > tight loop in the handler (perldoc perlipc):
>
> > > use POSIX ":sys_wait_h";
> > > $SIG{CHLD} = \&REAPER;
>
> > > # now do something that forks...
> > > ...
>
> > > sub REAPER { 1 while waitpid(-1, WNOHANG)) > 0; }
>
> > > --
> > > Charles DeRykus
>
> > Hi Charles - still doesn't wait - in fact the REAPER subroutine never
> > even gets called - I'm beginning to get back the 'flaw' concept...
>
> What's wrong with Xho's code earlier in the thread?
>
> $ perl -wle 'use strict; fork or exec "sleep " . $_*3 foreach 1..3 ;
> \
> my $x; do {$x=wait; print $x} until $x==-1'

You know what mon? Xho's program does indeed work in parallel AND
wait. Which means I really don't understand how to do this forking
( tee-hee) nonsense. I need to fix the flaw in MY architecture...
pg
pgodfrin [ Do, 17 Januar 2008 16:36 ] [ ID #1910947 ]

Re: Wait for background processes to complete

Gentle persons,

Xho was right from the start. Apparently all the samples from the
camel book, documentation for fork(), wait() and waitpid() are at the
least misleading - at the worse poorly written.

To begin with, if following the camel book's sample:

if ($pid=fork) { # parent here
} elsif { #child here
} # ...

One can indeed fork - but - the wait loop simply doesn't wait because
it returns -1 upon the first iteration.

The rest of the discussions in perliupc are quite interesting, but
useless in solving my problem here (although I did learn about signal
handlers a little bit).

In sum total here is the answer. Many, many thanks to Xho who was
right from the very beginning. Shame on the Perl documentation for
unnecessary obfuscation.

[at] fl= (</fausb/sample/*.txt>);
foreach ( [at] fl)
{
print "Copying $_ \n";
fork or exec("cp $_ $_.old") ;
}
do {$x=wait;} until $x==-1 ;
#{1 until -1==wait;}
print "\n<<<<< End of exercise >>>>>\n";
exit;

Incidentally Xho's other suggestion {1 until -1==wait; } also work.
pg
pgodfrin [ Do, 17 Januar 2008 17:38 ] [ ID #1910952 ]

Re: Wait for background processes to complete

On Jan 17, 10:38 am, pgodfrin <pgodf... [at] gmail.com> wrote:
> Gentle persons,
>
> Xho was right from the start. Apparently all the samples from the
> camel book, documentation for fork(), wait() and waitpid() are at the
> least misleading - at the worse poorly written.
>
> To begin with, if following the camel book's sample:
>
> if ($pid=fork) { # parent here
>
> } elsif { #child here
> } # ...
>
> One can indeed fork - but - the wait loop simply doesn't wait because
> it returns -1 upon the first iteration.
>
> The rest of the discussions in perliupc are quite interesting, but
> useless in solving my problem here (although I did learn about signal
> handlers a little bit).
>
> In sum total here is the answer. Many, many thanks to Xho who was
> right from the very beginning. Shame on the Perl documentation for
> unnecessary obfuscation.
>
> [at] fl= (</fausb/sample/*.txt>);
> foreach ( [at] fl)
> {
> print "Copying $_ \n";
> fork or exec("cp $_ $_.old") ;}
>
> do {$x=wait;} until $x==-1 ;
> #{1 until -1==wait;}
> print "\n<<<<< End of exercise >>>>>\n";
> exit;
>
> Incidentally Xho's other suggestion {1 until -1==wait; } also work.
> pg

and wiat; all by itself also works now...

sheesh!
pgodfrin [ Do, 17 Januar 2008 18:03 ] [ ID #1910954 ]

Re: Wait for background processes to complete

pgodfrin <pgodfrin [at] gmail.com> wrote:
> Gentle persons,
>
> Xho was right from the start. Apparently all the samples from the
> camel book, documentation for fork(), wait() and waitpid() are at the
> least misleading - at the worse poorly written.
>
> To begin with, if following the camel book's sample:
>
> if ($pid=fork) { # parent here
> } elsif { #child here
> } # ...
>
> One can indeed fork - but - the wait loop simply doesn't wait because
> it returns -1 upon the first iteration.

I suspect you are misinterpreting something. (For one thing, there is
no "wait loop" in what you have shown!) The code above should be
equivalent to my "fork or exec" code as long as the child block of the "if"
has an exec or a exit, so that the child itself it doesn't fall through
into the invisible wait loop.

Xho

--
-------------------- http://NewsReader.Com/ --------------------
The costs of publication of this article were defrayed in part by the
payment of page charges. This article must therefore be hereby marked
advertisement in accordance with 18 U.S.C. Section 1734 solely to indicate
this fact.
xhoster [ Do, 17 Januar 2008 18:14 ] [ ID #1910957 ]

Re: Wait for background processes to complete

On Jan 17, 11:14 am, xhos... [at] gmail.com wrote:
> pgodfrin <pgodf... [at] gmail.com> wrote:
> > Gentle persons,
>
> > Xho was right from the start. Apparently all the samples from the
> > camel book, documentation for fork(), wait() and waitpid() are at the
> > least misleading - at the worse poorly written.
>
> > To begin with, if following the camel book's sample:
>
> > if ($pid=fork) { # parent here
> > } elsif { #child here
> > } # ...
>
> > One can indeed fork - but - the wait loop simply doesn't wait because
> > it returns -1 upon the first iteration.
>
> I suspect you are misinterpreting something. (For one thing, there is
> no "wait loop" in what you have shown!) The code above should be
> equivalent to my "fork or exec" code as long as the child block of the "if"
> has an exec or a exit, so that the child itself it doesn't fall through
> into the invisible wait loop.
>
> Xho
>
> --
> --------------------http://NewsReader.Com/------------------ --
> The costs of publication of this article were defrayed in part by the
> payment of page charges. This article must therefore be hereby marked
> advertisement in accordance with 18 U.S.C. Section 1734 solely to indicate
> this fact.

Hi Xho,
OK - I didn't include the wait loop in the snippet simply for brevity.
I tried using the if logic and it just doesn't wait or fork properly.
Since I'm looping though filenames, this is inadequate. Unless proven
otherwise - I'll say the Camel book code is unclear and incorrect for
my purposes:

[at] fl= (</fausb/sample/*.txt>);
foreach ( [at] fl)
{
if($pid=fork)
{
print "Copying $_ to $_.old\n";
exec("cp $_ $_.old") ;
} elsif (defined $pid) { exit; }
} # end loop
wait;

print "\n<<<<< End of exercise >>>>>\n";
exit;

However, this works AND waits. But - this is very interesting - the
last file in the sample list is 3 or 4 times larger than the first few
files, which permits me to show that the wait does indeed wait for
child processes, but since the first fork replaces the parent process,
the wait command no longer has children to wait on and then continues
to the next statement, while the last cp command is still running.

[at] fl= (</fausb/sample/*.txt>);
foreach ( [at] fl)
{
print "Copying $_ to $_.old\n";
fork or exec("cp $_ $_.old") ;
} # end loop
wait;
print "\n<<<<< End of exercise >>>>>\n";
exit;

But - that's no good - which necessitates the loop you had suggested
from the start. Once again Xho - you da MAN!

[at] fl= (</fausb/sample/*.txt>);
foreach ( [at] fl)
{
print "Copying $_ to $_.old\n";
fork or exec("cp $_ $_.old") ;
} # end loop
do {$x=wait; print "$x\n"} until $x==-1 ;
print "\n<<<<< End of exercise >>>>>\n";
exit;
pgodfrin [ Do, 17 Januar 2008 19:44 ] [ ID #1910965 ]

Re: Wait for background processes to complete

On 2008-01-17 18:44, pgodfrin <pgodfrin [at] gmail.com> wrote:
> On Jan 17, 11:14 am, xhos... [at] gmail.com wrote:
>> pgodfrin <pgodf... [at] gmail.com> wrote:
>> > Gentle persons,
>>
>> > Xho was right from the start. Apparently all the samples from the
>> > camel book, documentation for fork(), wait() and waitpid() are at the
>> > least misleading - at the worse poorly written.

You may have been mislead, but please tell us what aspect of the
documentation mislead you.


>> > To begin with, if following the camel book's sample:
>>
>> > if ($pid=fork) { # parent here
>> > } elsif { #child here
>> > } # ...
>>
>> > One can indeed fork - but - the wait loop simply doesn't wait because
>> > it returns -1 upon the first iteration.

Compare this with your script:

> [at] fl= (</fausb/sample/*.txt>);
> foreach ( [at] fl)
> {
> if($pid=fork)
> {
> print "Copying $_ to $_.old\n";
> exec("cp $_ $_.old") ;
> } elsif (defined $pid) { exit; }
> } # end loop
> wait;
>
> print "\n<<<<< End of exercise >>>>>\n";
> exit;
>
> However, this works AND waits.

No, it doesn't. It doesn't work and it doesn't wait.

> But - this is very interesting - the
> last file in the sample list is 3 or 4 times larger than the first few
> files, which permits me to show that the wait does indeed wait for
> child processes, but since the first fork replaces the parent process,
> the wait command no longer has children to wait on and then continues
> to the next statement, while the last cp command is still running.

> [at] fl= (</fausb/sample/*.txt>);
> foreach ( [at] fl)
> {
> if($pid=fork)
> {

Here we are in the parent process ($pid != 0).

> print "Copying $_ to $_.old\n";
> exec("cp $_ $_.old") ;

You exec the cp command. This means that the parent process will now
execute "cp" instead of your script - after doing this it will exit.

> } elsif (defined $pid) {

Here we are in the child process.

> exit;

You exit immediately, so the child process does absolutely nothing. Why
fork at all if you don't want your child process to do anything?

> }

In any case, neither process will reach the end of the loop. So it will
copy exactly one file and

> } # end loop

since it never gets here it won't wait.
> wait;

You need to exec your program in the *child* process:


[at] fl= (</fausb/sample/*.txt>);
foreach ( [at] fl)
{
if($pid=fork)
{
# parent - do nothing
} elsif (defined $pid) {
# child
print "Copying $_ to $_.old\n";
exec("cp", $_, "$_.old") ;

# we won't get here if exec worked:
die "exec cp failed: $!";
}
} # end loop

# now wait for all the children:
do {$x=wait; print "$x\n"} until $x==-1 ;
hjp-usenet2 [ Fr, 18 Januar 2008 00:05 ] [ ID #1910977 ]

Re: Wait for background processes to complete

On 2008-01-17 00:52, comp.llang.perl.moderated <ced [at] blv-sam-01.ca.boeing.com> wrote:
> On Jan 16, 2:29 pm, pgodfrin <pgodf... [at] gmail.com> wrote:
>> On Jan 16, 4:17 pm, xhos... [at] gmail.com wrote:
>> > ## On Linux, wait returns -1 when there are no living children to wait for.
>> > 1 until -1==wait();
>>
>> > > exit;
>>
>
>> Thanks Xho - I've removed the signal handler, but it seems wait always
>> returns -1 so - the loop is a nop? Where in the code should it go?
>>
>
> I'll pipe in here since the 'quick 'n dirty' solution
> was mangled and diss'ed.
>
> The safest action is an asynchronous wait with a

Before 5.8.0 that was actually unsafe. But while it is now safe in perl
5.8.x (and 5.10.x), it still has the tiny flaw of absolutely *not* doing
what the OP wants. Xho's solution is safe (and was so in all perl
versions and does what the OP wants. Well, almost - wait can return -1
if it is interrupted so one should check $! in addition to the return
value.

hp
hjp-usenet2 [ Fr, 18 Januar 2008 00:12 ] [ ID #1910978 ]

Re: Wait for background processes to complete

pgodfrin <pgodfrin [at] gmail.com> wrote:
>
> Hi Xho,
> OK - I didn't include the wait loop in the snippet simply for brevity.

A little too much brevity often leads to many cycles of posting, which is
anything but brief!

> I tried using the if logic and it just doesn't wait or fork properly.
> Since I'm looping though filenames, this is inadequate. Unless proven
> otherwise - I'll say the Camel book code is unclear and incorrect for
> my purposes:

Peter has already described what went wrong here--you reversed the
parent and child roles in your code (which I snipped). If there is a
specific part of the perldoc that mislead you into doing that, let's figure
it out what that was and have it fixed. (The Camel book, I don't know how
to get that fixed so am slightly less interested in it.)

....

> However, this works AND waits. But - this is very interesting - the
> last file in the sample list is 3 or 4 times larger than the first few
> files, which permits me to show that the wait does indeed wait for
> child processes, but since the first fork replaces the parent process,
> the wait command no longer has children to wait on and then continues
> to the next statement, while the last cp command is still running.

I don't know what you meant by "the first fork replaces the parent process"
but whatever you meant I suspect it is heading the wrong way. What the
code below does is wait for one child, presumably whichever child
finishes first. Then it prints and exits, while N-1 other children are
still running. Some shells' "wait" can wait for all children. Perl's
"wait", like C's "wait", does not. It waits for one child.

>
> [at] fl= (</fausb/sample/*.txt>);
> foreach ( [at] fl)
> {
> print "Copying $_ to $_.old\n";
> fork or exec("cp $_ $_.old") ;
> } # end loop
> wait;
> print "\n<<<<< End of exercise >>>>>\n";
> exit;
>
> But - that's no good - which necessitates the loop you had suggested
> from the start.

The reason the loop works is that instead of just calling wait once, it
calls "wait" over and over until the OS says "Hey bozo, there is nothing
left to wait for". Well, it actually doesn't say that, it just returns -1,
but "Hey bozo..." is what it means.

Xho

--
-------------------- http://NewsReader.Com/ --------------------
The costs of publication of this article were defrayed in part by the
payment of page charges. This article must therefore be hereby marked
advertisement in accordance with 18 U.S.C. Section 1734 solely to indicate
this fact.
xhoster [ Fr, 18 Januar 2008 02:12 ] [ ID #1911636 ]

Re: Wait for background processes to complete

On Jan 17, 3:12 pm, "Peter J. Holzer" <hjp-usen... [at] hjp.at> wrote:
> On 2008-01-17 00:52, comp.llang.perl.moderated <c... [at] blv-sam-01.ca.boeing.com> wrote:
>
>
>
> > On Jan 16, 2:29 pm, pgodfrin <pgodf... [at] gmail.com> wrote:
> >> On Jan 16, 4:17 pm, xhos... [at] gmail.com wrote:
> >> > ## On Linux, wait returns -1 when there are no living children to wait for.
> >> > 1 until -1==wait();
>
> >> > > exit;
>
> >> Thanks Xho - I've removed the signal handler, but it seems wait always
> >> returns -1 so - the loop is a nop? Where in the code should it go?
>
> > I'll pipe in here since the 'quick 'n dirty' solution
> > was mangled and diss'ed.
>
> > The safest action is an asynchronous wait with a
>
> Before 5.8.0 that was actually unsafe. But while it is now safe in perl

Huh.. just for clarity, here's what I wrote:

use POSIX ":sys_wait_h";
$SIG{CHLD} = \&REAPER;
# now do something that forks...
...
sub REAPER { 1 while waitpid(-1, WNOHANG)) > 0; }

In fact, historically, there's a clear recommendation to tight-loop
exactly as shown because you may lose signals occurring in
near concurrency if you don't. Or are you
suggesting that an explicit wait on each of
the child processes would somehow be safer...

> 5.8.x (and 5.10.x), it still has the tiny flaw of absolutely *not* doing
> what the OP wants. Xho's solution is safe (and was so in all perl
> versions and does what the OP wants. Well, almost - wait can return -1
> if it is interrupted so one should check $! in addition to the return
> value.
>
You're right, a asynchronous wait would need to
save child pids and loop until they're reaped.
I believe a such a solution was already shown.

--
Charles DeRykus
Charles DeRykus [ Fr, 18 Januar 2008 02:34 ] [ ID #1911637 ]

Re: Wait for background processes to complete

On Jan 16, 9:37 pm, Ben Morrow <b... [at] morrow.me.uk> wrote:
> Quoth grocery_stocker <cdal... [at] gmail.com>:
>
>
>
> > On Jan 13, 10:09 pm, Ben Morrow <b... [at] morrow.me.uk> wrote:
>
> <snip>
> > > $SIG{CHLD} = sub {
> > > my ($pid, [at] died);
> > > push [at] died, $pid while $pid = waitpid -1, WNOHANG;
> > > delete [at] kids{ [at] died};
> > > };
> <snip>
> > > if ($pid) {
> > > $kids{$pid} = 1;
> > > return;
> > > }
> <snip>
> > > sub finish {
> > > waitpid $_, 0 for keys %kids;
> > > %kids = ();
> > > }
>
> > I really don't grasp the significance of having $kids{$pid} equal 1.
> > Can some enlighten me o this?
>
> It's one of the standard idioms for using a hash as a set. Every time we
> create a child, we add an entry to the hash; every time one dies on its
> own, we delete its entry. Then at the end we can use keys %pids to
> retrieve the list of pids we still need to wait for. The only thing that
> matters about %kids are its keys: we never use the values, so they can
> be set to anything. I prefer using 1 since then the values are all true;
> you can get slightly better memory use with
>
> $kids{$pid} = ();
>
> which inserts the key but doesn't create a value for it at all, but then
> you have to test with exists, which I find annoying. Since in this case
> I don't test for existance of keys at all, this doesn't matter: using 1 is
> just a habit.
>
> Ben


Okay, why would you have to test for exists if

$kids{$pid} = ();

just creates something like undef.
grocery_stocker [ Fr, 18 Januar 2008 03:02 ] [ ID #1911641 ]

Re: Wait for background processes to complete

On 2008-01-18 01:34, comp.llang.perl.moderated <ced [at] blv-sam-01.ca.boeing.com> wrote:
> On Jan 17, 3:12 pm, "Peter J. Holzer" <hjp-usen... [at] hjp.at> wrote:
>> On 2008-01-17 00:52, comp.llang.perl.moderated <c... [at] blv-sam-01.ca.boeing.com> wrote:
>>
>> > On Jan 16, 2:29 pm, pgodfrin <pgodf... [at] gmail.com> wrote:
>> >> On Jan 16, 4:17 pm, xhos... [at] gmail.com wrote:
>> >> > ## On Linux, wait returns -1 when there are no living children to wait for.
>> >> > 1 until -1==wait();
>>
>> >> > > exit;
>>
>> >> Thanks Xho - I've removed the signal handler, but it seems wait always
>> >> returns -1 so - the loop is a nop? Where in the code should it go?
>>
>> > I'll pipe in here since the 'quick 'n dirty' solution
>> > was mangled and diss'ed.
>>
>> > The safest action is an asynchronous wait with a
>>
>> Before 5.8.0 that was actually unsafe. But while it is now safe in perl
>
> Huh.. just for clarity, here's what I wrote:
>
> use POSIX ":sys_wait_h";
> $SIG{CHLD} = \&REAPER;
> # now do something that forks...
> ...
> sub REAPER { 1 while waitpid(-1, WNOHANG)) > 0; }
>
> In fact, historically, there's a clear recommendation to tight-loop
> exactly as shown because you may lose signals occurring in
> near concurrency if you don't.

The problem with this approach is that until 5.8.0 (when "safe signals"
were introduced), the REAPER function would be called as soon as the
signal arrived regardless of what the perl interpreter was doing at the
time - there was a very real risk that this would crash the perl
interpreter (in a real world application which forked about 50,000 to
100,000 times a day, the parent process would crash every few days with
perl 5.6.0). In C the POSIX standard explicitely states which functions
are safe inside a signal handler (and the rest has to be considered
unsafe), but for perl no such list existed (so everything has to be
considered unsafe). In perl 5.8.0, the "real" signal handler only notes
that a signal arrived, and perl will than invoke sub REAPER when it can
safely do this (which may be quite some time later).


> Or are you suggesting that an explicit wait on each of the child
> processes would somehow be safer...

Avoiding signal handles was indeed "somehow safer" before 5.8.0,
because signal handlers were fundamentally unsafe (and arguably broken)
in perl.

But that was only a side note. My real argument was that this code has a
completely different purpose: It "reaps" children as soon as they exit
to avoid zombies. This is useful for long-running server processes which
don't really want to wait for their children - they just want to fire
them off and then forget about them. But the OP explicitely wants to
wait for his children so that is what he should do. There is no need for
any signal handlers - they just add complexity which isn't needed and
obscure the purpose of the code.


>> 5.8.x (and 5.10.x), it still has the tiny flaw of absolutely *not* doing
>> what the OP wants. Xho's solution is safe (and was so in all perl
>> versions and does what the OP wants. Well, almost - wait can return -1
>> if it is interrupted so one should check $! in addition to the return
>> value.
>>
> You're right, a asynchronous wait would need to
> save child pids and loop until they're reaped.

Yes. But why would you want to do that if it can be done a lot simpler
and more straightforward?

hp
hjp-usenet2 [ Fr, 18 Januar 2008 16:11 ] [ ID #1911664 ]

Re: Wait for background processes to complete

On 2008-01-18 02:02, grocery_stocker <cdalten [at] gmail.com> wrote:
> On Jan 16, 9:37 pm, Ben Morrow <b... [at] morrow.me.uk> wrote:
>> The only thing that matters about %kids are its keys: we never use
>> the values, so they can be set to anything. I prefer using 1 since
>> then the values are all true; you can get slightly better memory use
>> with
>>
>> $kids{$pid} = ();
>>
>> which inserts the key but doesn't create a value for it at all, but
>> then you have to test with exists, which I find annoying. Since in
>> this case I don't test for existance of keys at all, this doesn't
>> matter: using 1 is just a habit.
>
> Okay, why would you have to test for exists if
>
> $kids{$pid} = ();
>
> just creates something like undef.

Consider:

#!/usr/bin/perl
use warnings;
use strict;

my %kids;

$kids{3} = ();
$kids{5} = ();

for (1 .. 9) {
print "$_\n" if is_kid($_);
}

sub is_kid {
return exists($kids{$_[0]});
}
__END__
3
5

Please find an implementation for sub is_kid which doesn't use exists.

hp
hjp-usenet2 [ Fr, 18 Januar 2008 16:20 ] [ ID #1911666 ]

Re: Wait for background processes to complete

On Jan 18, 7:11 am, "Peter J. Holzer" <hjp-usen... [at] hjp.at> wrote:
> On 2008-01-18 01:34, comp.llang.perl.moderated <c... [at] blv-sam-01.ca.boeing.com> wrote:
>
>
>
> > On Jan 17, 3:12 pm, "Peter J. Holzer" <hjp-usen... [at] hjp.at> wrote:
> >> On 2008-01-17 00:52, comp.llang.perl.moderated <c... [at] blv-sam-01.ca.boeing.com> wrote:
>
> >> > On Jan 16, 2:29 pm, pgodfrin <pgodf... [at] gmail.com> wrote:
> >> >> On Jan 16, 4:17 pm, xhos... [at] gmail.com wrote:
> >> >> > ## On Linux, wait returns -1 when there are no living children to wait for.
> >> >> > 1 until -1==wait();
>
> >> >> > > exit;
>
> >> >> Thanks Xho - I've removed the signal handler, but it seems wait always
> >> >> returns -1 so - the loop is a nop? Where in the code should it go?
>
> >> > I'll pipe in here since the 'quick 'n dirty' solution
> >> > was mangled and diss'ed.
>
> >> > The safest action is an asynchronous wait with a
>
> >> Before 5.8.0 that was actually unsafe. But while it is now safe in perl
>
> > Huh.. just for clarity, here's what I wrote:
>
> > use POSIX ":sys_wait_h";
> > $SIG{CHLD} = \&REAPER;
> > # now do something that forks...
> > ...
> > sub REAPER { 1 while waitpid(-1, WNOHANG)) > 0; }
>
> > In fact, historically, there's a clear recommendation to tight-loop
> > exactly as shown because you may lose signals occurring in
> > near concurrency if you don't.
>
> The problem with this approach is that until 5.8.0 (when "safe signals"
> were introduced), the REAPER function would be called as soon as the
> signal arrived regardless of what the perl interpreter was doing at the
> time - there was a very real risk that this would crash the perl
> interpreter (in a real world application which forked about 50,000 to
> 100,000 times a day, the parent process would crash every few days with
> perl 5.6.0). In C the POSIX standard explicitely states which functions
> are safe inside a signal handler (and the rest has to be considered
> unsafe), but for perl no such list existed (so everything has to be
> considered unsafe). In perl 5.8.0, the "real" signal handler only notes
> that a signal arrived, and perl will than invoke sub REAPER when it can
> safely do this (which may be quite some time later).
>
> > Or are you suggesting that an explicit wait on each of the child
> > processes would somehow be safer...
>
> Avoiding signal handles was indeed "somehow safer" before 5.8.0,
> because signal handlers were fundamentally unsafe (and arguably broken)
> in perl.

Hm, I thought I recalled that, even with
Perl's broken pre-5.8 signal handling, the
issue was most likely to surface with op's
not on POSIX's safe list. Something like
'waitpid', which is on POSIX's safe list,
in a simple loop was unlikely to cause a
problem.


>
> But that was only a side note. My real argument was that this code has a
> completely different purpose: It "reaps" children as soon as they exit
> to avoid zombies. This is useful for long-running server processes which
> don't really want to wait for their children - they just want to fire
> them off and then forget about them. But the OP explicitely wants to
> wait for his children so that is what he should do. There is no need for
> any signal handlers - they just add complexity which isn't needed and
> obscure the purpose of the code.
>
> >> 5.8.x (and 5.10.x), it still has the tiny flaw of absolutely *not* doing
> >> what the OP wants. Xho's solution is safe (and was so in all perl
> >> versions and does what the OP wants. Well, almost - wait can return -1
> >> if it is interrupted so one should check $! in addition to the return
> >> value.
>
> > You're right, a asynchronous wait would need to
> > save child pids and loop until they're reaped.
>
> Yes. But why would you want to do that if it can be done a lot simpler
> and more straightforward?
>

Yes I agree that's probably true here but, as you mention, you'd have
to check for -1 because the process was reaped, stopped, or terminated
by some signal for instance. And, if you're concerned about zombies,
you really need to keep a list of pids to wait on. To me the solutions
are very close modulo the signal function setup. Even outside the
daemon
setting, I like the signal solution which handles
the reaping as soon as it occurs and bundles child cleanup neatly in a
separate sub.

--
Charles DeRykus
Charles DeRykus [ Fr, 18 Januar 2008 18:30 ] [ ID #1911675 ]

Re: Wait for background processes to complete

Gentle Persons,
This was a lot of fun. I would like to respond to the various
observations, especially the ones about the Perl Documentation being
misleading.

To begin with, I apologize for my last post (the long one) - upon re-
reading it my language was not clear. I should have said "the
following code works" as opposed to simply "this works AND waits". I
was referring to the code below that sentence. Sorry.

To restate the original task I wanted to solve:

To be able to execute commands in the background and wait for their
completion.

The documentation I am referring to is http://perldoc.perl.org/.

If you search on the concept of "background processes" this
documentation points you to the following in the Language reference >
perlipc > Background Process :
<begin quote>
You can run a command in the background with:

system("cmd &");

The command's STDOUT and STDERR (and possibly STDIN, depending on your
shell) will be the same as the parent's. You won't need
to catch SIGCHLD because of the double-fork taking place (see below
for more details).
<end quote>
There is no further reference to a "double fork" (except in the
perlfaq8 and only in the context of zombies, which it says are not an
issue using system("cmd &") ). This is confusing.

The documentation for wait(), waitpid() and fork() do not explain that
the executing code should be placed in the "child" section of the if
construct. Some of the examples in perlipc show code occurring in both
the parent and the child section - so it is still not clear. If it
were, why was I insisting on trying to execute the "cp" command in the
parent section? So, thank you Peter for clearing that up. To be fair,
the only place where the "if" construct is indeed placed on paper (or
virtual paper) is the camel book - but it is also not clear where the
code should be placed. But clearly, that is clear now :).

Furthermore, while the perlipc section is quite verbose, nowhere is
the code snippet do {$x=wait; print "$x\n"} until $x==-1 or any
variation of that wait() call mentioned. There are references to a
while loop and the waitpid() function, but being in the context of a
signal handler and 'reaping' - it is not clear.

So, once again many thanks for the help. I would like to know, Peter,
are you in a position to amend the documentation? Also, the perlfaq8
does come closer to explaining, but it is simply not clear how the
fork process will emulate the Unix background operator (&). So how can
we make this better? How's about this:

In the perlipc, under background tasks. make the statement - "the call
system("cmd &") will run the cmd in the background, but will spawn a
shell to execute the command, dispatch the command, terminate the
shell and return to the calling program. The calling program will lose
the ability to wait for the process as is customary with the shell
script command 'wait'. In order to both execute one or more programs
in the background and have the calling program wait for the executions
to complete it will be necessary to use the fork() function."

Then in the fork section. Show a simple example like the ones we have
been working with AND show a simple approach to using the wait
function. Furthermore - add sample code to the wait() and fork()
functions that are simple and realistic, unlike the code same in the
waitpid() function.

In closing, it is perhaps non-intuitive to me that a fork process
should have the child section actually executing the code, but I ask
you how one can intuit that from the sample in the camel book and the
samples in the http://perldoc.perl.org/. To really drive the point
home, Xho's code:

fork or exec("cp $_ $_.old") ;
do {$x=wait;} until $x==-1 ;

Is STILL not intuitive that the child is executing the code!

All in all, with the collective help of y'all I been able to
successfully accomplish my goal, but man it was an uphill battle that
could have been very easily solved with better documentation. But -
what I can't figure out is why I had to embark on this journey in a
new posting - has no-one needed to do this before? Oh well...

so long and thanks for all the fish,
pg
pgodfrin [ Fr, 18 Januar 2008 18:47 ] [ ID #1911677 ]

Re: Wait for background processes to complete

On 2008-01-18 17:47, pgodfrin <pgodfrin [at] gmail.com> wrote:
> This was a lot of fun. I would like to respond to the various
> observations, especially the ones about the Perl Documentation being
> misleading.
[...]
> To restate the original task I wanted to solve:
>
> To be able to execute commands in the background and wait for their
> completion.
>
> The documentation I am referring to is http://perldoc.perl.org/.
>
> If you search on the concept of "background processes" this
> documentation points you to the following in the Language reference >
> perlipc > Background Process :
><begin quote>
> You can run a command in the background with:
>
> system("cmd &");
>
> The command's STDOUT and STDERR (and possibly STDIN, depending on your
> shell) will be the same as the parent's. You won't need
> to catch SIGCHLD because of the double-fork taking place (see below
> for more details).
><end quote>
> There is no further reference to a "double fork" (except in the
> perlfaq8 and only in the context of zombies, which it says are not an
> issue using system("cmd &") ). This is confusing.

I find it more confusing that this seems to be in the section with the
title "Using open() for IPC". I fail to see what one has to do with the
other.

There is a general problem with perl documentation: Perl evolved in the
Unix environment, and a lot of the documentation was written at a time
when the "newbie perl programmer" could be reasonably expected to have
already some programming experience on Unix (in C, most likely) and know
basic Unix concepts like processes, fork(), filehandles, etc. So in a
lot of places the documentation doesn't answer the question "how can I
do X on Unix?" but the question "I already know how to do X in C, now
tell me how I can do it in perl!". When you lern Perl without knowing
Unix first, this can be confusing, because the Perl documentation
generelly explains only Perl, but not Unix.

I am not sure if that should be fixed at all: It's the perl
documentation and not the unix documentation after all, and perl isn't
unix specific, but has been ported to just about every OS.


> The documentation for wait(), waitpid() and fork() do not explain that
> the executing code should be placed in the "child" section of the if
> construct.

Of course not, that would be wrong. There can be code in both (if you
wanted one process to do nothing, why fork?). What the parent should do
and what the child should do depend on what you want them to do. It just
happened that for your particular problem the parent had nothing to do
between forking off children.

> Some of the examples in perlipc show code occurring in both
> the parent and the child section - so it is still not clear. If it
> were, why was I insisting on trying to execute the "cp" command in the
> parent section?

I don't know. What did you expect that would do?

Your problem was:

I want a process to gather a list of files. Then, for each file, it
should start another process which copies the file. These processes
should run in parallel. Finally, it should wait for all these processes
to terminate, and then terminate itself.

Even this description makes it rather implicit, that the original
process creates children and then the children do the copying. If you
add the restriction that a process can only wait for its children, any
other solution becomes extremely awkward.

Besides it is exactly the same what your shell script did: The shell
(the parent process) created child processes in a loop, each child
process executed one cp command, and finally the parent waited for all
the children.


> Furthermore, while the perlipc section is quite verbose, nowhere is
> the code snippet do {$x=wait; print "$x\n"} until $x==-1 or any
> variation of that wait() call mentioned.

Again, this is a solution to your specific problem. You said you wanted
to wait for all children, so Xho wrote a loop which would do that. This
is a rather rare requirement - I think I needed it maybe a handful of
times in 20+ years of programming outside of a child reaper function.


> There are references to a
> while loop and the waitpid() function, but being in the context of a
> signal handler and 'reaping' - it is not clear.

This is the one situation where this construct is frequently used. It
can happen that several children die before the parent can react to the
signal - in this case the reaper function will be called only once, but
it must wait for several children. This isn't obvious, so the docs
mention it.

However, in your case you *know* you started several children and you
*want* to wait for all of them, so it's obvious that you need a loop. This
hasn't anything to do with perl, it's just a requirement of your
problem.


> So, once again many thanks for the help. I would like to know, Peter,
> are you in a position to amend the documentation? Also, the perlfaq8
> does come closer to explaining, but it is simply not clear how the
> fork process will emulate the Unix background operator (&). So how can
> we make this better? How's about this:

fork doesn't "emulate &". fork is one of the functions used by the shell
to execute commands. Basically, the shell does this in a loop:

display the prompt
read the next command
fork
in the child:
execute the command, then exit
in the parent:
if the command did NOT end with &:
wait for the child to terminate

So the Shell always forks before executing commands and it always
executes them in a child process. But normally it waits for the child
process to terminate before displaying the next prompt. If you add the
"&" at the end of the line, it doesn't wait but displays the next prompt
immediately.

(ok, that's a bit too simplistic, but I don't want to go into the arcana
of shell internals here - that would be quite off-topic).



> In the perlipc, under background tasks. make the statement - "the call
> system("cmd &") will run the cmd in the background, but will spawn a
> shell to execute the command, dispatch the command, terminate the
> shell and return to the calling program. The calling program will lose
> the ability to wait for the process as is customary with the shell
> script command 'wait'. In order to both execute one or more programs
> in the background and have the calling program wait for the executions
> to complete it will be necessary to use the fork() function."

I think that would confuse just about anybody who doesn't have exactly
your problem for exactly the same reason you were confused by the
"double fork". It's very specific and should be clear to anyone who
knows what system does and what a unix shell does when you use "&" - I
suspect that sentence about the double fork was added after a discussion
like this one. But I agree that fork should definitely be mentioned here.
system("cmd &") almost never what you would want to do.


> Then in the fork section. Show a simple example like the ones we have
> been working with AND show a simple approach to using the wait
> function.
> Furthermore - add sample code to the wait() and fork()
> functions that are simple and realistic,

fork and wait are very simple building blocks which can be combined in a
lot of different ways. Any sample code here can cover only basic
constructs like

my $pid = fork();
if (!defined $pid) {
die "fork failed: $!";
} elsif ($pid == 0) {
# child does something here
# ...
exit;
} else {
# parent does something here
# ...
# and then waits for child:
waitpid($pid, 0);
}

More complex examples should go into perlipc (which needs serious
cleanup, IMHO).

> unlike the code same in the waitpid() function.

That code is simple and realistic.


> In closing, it is perhaps non-intuitive to me that a fork process
> should have the child section actually executing the code,

If you don't want the child process to do anything, why would you create
it in the first place?

> but I ask you how one can intuit that from the sample in the camel
> book and the samples in the http://perldoc.perl.org/. To really drive
> the point home, Xho's code:
>
> fork or exec("cp $_ $_.old") ;
> do {$x=wait;} until $x==-1 ;
>
> Is STILL not intuitive that the child is executing the code!

True. This code isn't meant to be intuitive. It's meant to be short.
I wouldn't write that in production code, much less in an answer to a
newbie question.

hp
hjp-usenet2 [ Fr, 18 Januar 2008 22:17 ] [ ID #1911688 ]
Perl » comp.lang.perl.misc » Wait for background processes to complete

Vorheriges Thema: FAQ 8.17 How can I measure time under a second?
Nächstes Thema: Pipe input over several scripts