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

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.

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

        Thank you very much. I want to rename the name of $filename after all child process finished writing. Each child process will write to $filename cumulatively. The purpose of the script is to test network connection for every host. In the "for" loop, itis to create child processes to test the connection concurrencily, and meanwhile write to $filename. The alarm is for network connection timeout, if after 60s, the connection is still unable to setup, then will go to $SIG{ALRM} to print error message.
        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 = "/var/log/a.tmp"; my $newfilename = "/var/log/a.log"; open (my $fh, ">", $filename) or die "Could not open file '$filename' +$!\n"; my $time = strftime('%d-%m-%Y %H:%M:%S',localtime); for (my $index=0; $index <= $#$targets; $index++){ my $array = $targets->[$index]{label}; my $hostaddress = $array->{ip}; $time = strftime('%d-%m-%Y %H:%M:%S',localtime); defined(my $pid = fork) or die "fork failed: $!"; unless( defined($pid) ) { flock $fh, LOCK_EX; print $fh "Can't execute check: can't fork(): $!\n"; flock $fh, LOCK_UN; } unless($pid) { # child print "child: $$\n"; my $var; eval { $var = #setup a network connection...; $SIG{ALRM} = sub { flock $fh, LOCK_EX; print $fh "\n"; flock $fh, LOCK_UN;}; alarm(60); }; if( $@ ) { flock $fh, LOCK_EX; print $fh "Connection failed $@\n"; flock $fh, LOCK_UN; } unless( $var ) { flock $fh, LOCK_EX; print $fh "Connection failed"; flock $fh, LOCK_UN; } else { flock $fh, LOCK_EX; print $fh "Connection failed\n"; flock $fh, LOCK_UN; } close($fh); exit; # exit child process } waitpid($pid,0); } print "Parent Process"; close($fh); # Close file handler $fh rename ($filename, $newfilename) or die "Error in renaming $!"; alarm(0);
        I also run a test, if the network cannot be setup successfully, it is not concurrency.. I pasted part of the logs as below, each line of logs were print one by one. But I want to get all the connection status concurrency...
        10-09-2022 06:24:10 1.1.1.1 Can't connect to 1.1.1.1 10-09-2022 06:25:10 2.2.2.2 Can't connect to 2.2.2.2 10-09-2022 06:26:10 3.3.3.3 Can't connect to 3.3.3.3 10-09-2022 06:27:11 4.4.4.4 Can't connect to 4.4.4.4 ...