wonderG has asked for the wisdom of the Perl Monks concerning the following question:

for (my $index=0; $index <= $#$array; $index++){ defined(my $pid = fork) or die "fork failed: $!"; unless( defined($pid) ) { flock $logfile, LOCK_EX; print $logfile "OK $!\n"; flock $logfile, LOCK_UN; } unless($pid) { # child print "child: $$\n"; eval { ....... }; if( $@ ) { flock $logfile, LOCK_EX; print $logfile "ok"; flock $logfile, LOCK_UN; } unless( .. ) { flock $logfile, LOCK_EX; print $logfile "ok"; flock $logfile, LOCK_UN; else { flock $fh, LOCK_EX; print $fh "ok"; flock $fh, LOCK_UN; } close($fh); close($logfile); exit; # exit child process } if(wait() == -1){ print "Parent Process"; close($fh); # Close file handler $fh close($logfile); # Close file handler $logfile alarm(0); } }
The above if block if(wait() == -1) can not be executed...could you help to check if there is any errors in my code?

Replies are listed 'Best First'.
Re: Multiprocess - child process cannot be finished successfully
by kcott (Archbishop) on Sep 09, 2022 at 12:43 UTC

    G'day wonderG,

    Welcome to the Monastery.

    "The above if block if(wait() == -1) can not be executed..."

    The short answer is because "wait() == -1" is FALSE.

    "...could you help to check if there is any errors in my code"

    You've presented us with incomplete code. This just raises a lot of questions and means we have to engage in guesswork if we were to attempt an answer.

    • Are $logfile and $fh really package variables?
    • What was the original timeout for alarm()?
    • What's the value of $SIG{ALRM}?
    • Was $SIG{ALRM} localised?
    • What are we not seeing in '.......' and '..'?

    Please cut down your code to a minimum, that we can run, and reproduces the problem; as described in "Short, Self-Contained, Correct Example". Also, follow the guidelines in "How do I post a question effectively?".

    It would also be preferable unless you do use potentially confusing constructs like "unless (...) {...} else {...}". Confused? Try s/unless you do/if you don't/. :-)

    Here's some very basic code that uses wait() and doesn't have a problem.

    #!/usr/bin/env perl use strict; use warnings; my $pid = fork(); if (defined $pid) { if ($pid) { print "Parent: $$; Child: $pid\n"; my $wait = wait(); print "Parent waited on Child: $wait\n"; } else { print "Child: $$\n"; exit; } } else { warn 'Fork failed!'; }

    Sample output:

    Parent: 553; Child: 554 Child: 554 Parent waited on Child: 554

    This may highlight your problem and allow you to fix it. If not, add small amounts of code until your problem resurfaces; then post that and ask for our help.

    See also waitpid().

    — Ken

      Really many thanks for kind reply.
Re: Multiprocess - child process cannot be finished successfully
by bliako (Abbot) on Sep 09, 2022 at 12:45 UTC

    wait()'ing for a child process to terminate is correct. But expecting wait() to return -1 on success is causing your block not to execute at all because wait() can also return the PID of the process it found just terminated. E.g. from the wait documentation:

    wait: Behaves like wait(2) on your system: it waits for a child process to terminate and returns the pid of the deceased process, or -1 if there are no child processes.

    So you just need to remove that == -1 check.

    That said, wait() waits for ANY child process including those by a system command. Why not being explicit and wait for YOUR OWN child with waitpid($pid, 0)?

    bw, bliako

    Edit: kcott made the same diagnosis a few minutes earlier, though I read it after posting.

      use strict; use Fcntl qw(:DEFAULT :flock); use FindBin qw($Bin); use lib "$Bin"; use JSON; use POSIX; my $JSON_FILE = $ARGV[0]; open my $file, '<', $JSON_FILE or die("$JSON_FILE Could not open file: + $!\n"); my $data; eval { $data = decode_json(<$file>); print $data; }; if ( $@ ){ print "Json file parsing failed.\n"; } my $targets = $data; my $filename = "/tmp"; my $newfilename = "/filename"; open (my $fh, ">", $filename) or die "Could not open file '$filename' +$!\n"; print $fh "message..\n"; print $fh "message...\n"; my $time = strftime('%d-%m-%Y %H:%M:%S',localtime); my $logfile = "/var/log/mylog.log"; open (my $logfile, ">>", $logfile) or die "Could not open file '$logfi +le' $!"; for (my $index=0; $index <= $#$targets; $index++){ my $array = $targets->[$index]{labels}; my $name = $array->{name}; $time = strftime('%d-%m-%Y %H:%M:%S',localtime); # Set a timeout period $SIG{ALRM} = sub { flock $logfile, LOCK_EX; print $logfile "message...\n"; flock $logfile, LOCK_UN; flock $fh, LOCK_EX; print $fh "message...\n"; flock $fh, LOCK_UN; alarm(60); defined(my $pid = fork) or die "fork failed: $!"; unless( defined($pid) ) { flock $logfile, LOCK_EX; print $logfile "message...\n"; flock $logfile, LOCK_UN; } unless($pid) { # child print "child: $$\n"; my $var; eval { do something here... }; if( $@ ) { flock $logfile, LOCK_EX; print $logfile "message...\n"; flock $logfile, LOCK_UN; } unless( $var ) { flock $logfile, LOCK_EX; print $logfile "message...\n"; flock $logfile, LOCK_UN; flock $fh, LOCK_EX; print $fh "message...\n"; flock $fh, LOCK_UN; } else { flock $fh, LOCK_EX; print $fh "message...\n"; flock $fh, LOCK_UN; flock $logfile, LOCK_EX; print $logfile "message...\n"; flock $logfile, LOCK_UN; } close($fh); close($logfile); exit; # exit child process } waitpid($pid,0); # could I refine like this? print "Parent Process"; close($fh); # Close file handler $fh close($logfile); # Close file handler $logfile rename ($filename, $newfilename) or die "Error in renaming $!"; alarm(0); }
      Thank you very much. I just refined my code as above. I have very less exeprience is Perl, could you please help to review if everything is ok? I just debug my code, it threw an error during "rename" - Error in renaming No such file or directory. I want to rename the filename after everyhing is written into the file.

        WonderG your usage of waitpid looks ok to me. The rename error: your $filename is /tmp which in a Unix-based system is usually a directory. So perhaps, you meant it as a basename and $filename changes in every run, in which case investigate using die "Error in renaming '$filename' to '$newfilename', $!" and check that you have read permissions for the source (and it does exist) and write permissions in the directory of the destination.

Re: Multiprocess - child process cannot be finished successfully
by tybalt89 (Monsignor) on Sep 12, 2022 at 17:07 UTC

    Here's my guess for what you're trying to do. (Leaving the rename part incomplete in honor of your leaving the connection part incomplete.)

    #!/usr/bin/perl use strict; # https://perlmonks.org/?node_id=11146781 use warnings; use Path::Tiny; use Time::HiRes qw( time ); use IO::Socket; my $port = 3143; # to my https://rosettacode.org/wiki/Hunt_the_Wumpus# +Perl my @ips = map "192.168.1.$_:$port", 10 .. 20; # FIXME for testing my $logfile = path( "/tmp/d.11146781,log" ); # FIXME filename my $timeoutin = 0.1; # FIXME short for testin +g $logfile->spew( localtime() . " begin\n" ); my $start = time; for my $ip ( @ips ) { if( my $pid = fork ) {} # parent elsif( defined $pid ) # child { my $status = IO::Socket::INET->new( # test for connection PeerAddr => $ip, Timeout => $timeoutin, ) ? 'ok' : $@ =~ s/.*: //r; $logfile->append( sprintf "%s %s in %.3fs\n", $ip, $status, time - + $start ); exit; } else { die "$! on fork" } # failure } 1 while wait >= 0; $logfile->append( localtime() . " end\n" ); print $logfile->slurp; # FIXME for testing # rename here...

    Outputs:

    Mon Sep 12 09:54:46 2022 begin 192.168.1.13:3143 ok in 0.003s 192.168.1.14:3143 timeout in 0.102s 192.168.1.12:3143 timeout in 0.102s 192.168.1.16:3143 timeout in 0.102s 192.168.1.19:3143 timeout in 0.102s 192.168.1.10:3143 timeout in 0.103s 192.168.1.15:3143 timeout in 0.103s 192.168.1.11:3143 timeout in 0.103s 192.168.1.20:3143 timeout in 0.103s 192.168.1.18:3143 timeout in 0.103s 192.168.1.17:3143 timeout in 0.104s Mon Sep 12 09:54:46 2022 end

    Note: I am using Path::Tiny ->append because it does file locking. I consider the fact that it is also doing open and close as insignificant.

Re: Multiprocess - child process cannot be finished successfully
by Corion (Patriarch) on Sep 09, 2022 at 11:14 UTC

    What do you mean by "the block cannot be executed"?

    Is there some output? Does the wait() never return?

    What is the output in your logfile?

Re: Multiprocess - child process cannot be finished successfully
by Fletch (Bishop) on Sep 11, 2022 at 12:35 UTC

    More of an aside but . . . you're jumping in the deep end trying to roll your own multiprocess networking and file i/o code. Standing on the existing shoulders of POE or AnyEvent may let you at least abstract those bits and concentrate on what you want done when specific things ("events" as it were) occur.

    The cake is a lie.
    The cake is a lie.
    The cake is a lie.

Re: Multiprocess - child process cannot be finished successfully
by tybalt89 (Monsignor) on Sep 13, 2022 at 17:42 UTC

    As an alternative, instead of forking, just start all the connection attempts in non-blocking mode, then after the appropriate time, check for connections, sort of like this:

    #!/usr/bin/perl use strict; # https://perlmonks.org/?node_id=11146781 use warnings; use Path::Tiny; use IO::Socket; my $port = 3143; # FIXME to my https://rosettacode.org/wiki/Hunt_the_W +umpus#Perl my @ips = map "192.168.1.$_:$port", 10 .. 20; # FIXME for testing my $logfile = path( "/tmp/d.11146781,log" ); # FIXME filename my $timeoutin = 0.1; # FIXME short for testin +g my $log = localtime() . " begin\n"; my %sockets; $sockets{ $_ } = IO::Socket::INET->new( PeerAddr => $_, Blocking => 0 ) or $log .= "$_ fail $@\n", next for @ips; # start all connections select undef, undef, undef, $timeoutin; # the time allowed $log .= "$_ " . ( $sockets{$_}->connected ? "ok\n" : "failed\n" ) for grep $sockets{$_}, @ips; $logfile->spew( $log, localtime() . " end\n" ); print $logfile->slurp; # FIXME for testing #rename here...

    Which on my machine outputs:

    Tue Sep 13 10:26:54 2022 begin 192.168.1.10:3143 failed 192.168.1.11:3143 failed 192.168.1.12:3143 ok 192.168.1.13:3143 ok 192.168.1.14:3143 failed 192.168.1.15:3143 ok 192.168.1.16:3143 failed 192.168.1.17:3143 failed 192.168.1.18:3143 failed 192.168.1.19:3143 failed 192.168.1.20:3143 failed Tue Sep 13 10:26:54 2022 end

    No forks, no 'wait's, no 'alarm's, no 'flock's and the system does all the concurrency for you :)

A reply falls below the community's threshold of quality. You may see it by logging in.