in reply to Multiprocess - child process cannot be finished successfully

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.

Replies are listed 'Best First'.
Re^2: Multiprocess - child process cannot be finished successfully
by wonderG (Novice) on Sep 09, 2022 at 13:21 UTC
    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.

        Thank you very much. I refined my code like below. I put waitpid in the "for" loop, but move print and rename out of the "for" loop, then everything is ok. Is it the right behavior?
        close($fh); close($logfile); exit; # exit child process } waitpid($pid,0); } print "Parent Process"; close($fh); # Close file handler $fh close($logfile); # Close file handler $logfile rename ($filename, $newfilename) or die "Error in renaming $!"; # Rena +me the temporary to avoid node exporter seeing half a file. alarm(0);