in reply to Re: Multiprocess - child process cannot be finished successfully
in thread Multiprocess - child process cannot be finished successfully

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.
  • Comment on Re^2: Multiprocess - child process cannot be finished successfully
  • Download Code

Replies are listed 'Best First'.
Re^3: Multiprocess - child process cannot be finished successfully
by bliako (Abbot) on Sep 09, 2022 at 14:47 UTC

    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);

        It really depends on what kind of processing you are doing in the child and whether $filename should be renamed only outside the loop, because that's what you just did when you added that missing curly bracket. Is each child writing to the $filename cumulatively and only when all children are finished writing to it you want to rename it? To me it does not sound right. But I don't know what you are trying to do and your code makes it difficult to guess. And the alarm call, setting the alarm(60) and then canceling it (alarm(0), inside or outside the loop?) makes it even more difficult ... Now that you have the fork semantics working, try and isolate what you want to go inside the alarm in a new function and ask yourself when should files be closed, alarms cancelled and files renamed. Inside or outside the loop it may not matter for Perl, it may not be a syntax error but you may end up blowing up your cpu :) So, step back and think the problem on paper without writing code for a while.