I need to ensure that only one copy of my Perl script is running at a time. According to the suggestions here I wrote a sub to do the check:
sub check_instances {
open my $fh, '<', $0 or die $!;
unless (flock($fh, LOCK_EX|LOCK_NB)) {
print "$0 is already ru开发者_如何学JAVAnning. Exiting.\n";
exit 1;
}
}
But it doesn't work. What can be the issue?
You're using a lexical filehandle scoped inside the sub. When check_instances
returns, the filehandle is automatically closed, which releases the lock. So you'll never see a conflict unless two copies check at exactly the same time.
Ensure that the filehandle remains open as long as the script is running (or as long as you want to maintain the lock). For example:
{
my $fh;
sub check_instances {
return if $fh; # We already checked
open $fh, '<', $0 or die $!;
unless (flock($fh, LOCK_EX|LOCK_NB)) {
print "$0 is already running. Exiting.\n";
exit 1;
}
}
} # end scope of $fh
This would also be a good place to use a state
variable, if you can require Perl 5.10.
You can check the process list for other instances (Proc::ProcessTable can help), but a common route taken by unix programs in many languages is to create a pid file -- see File::Pid.
The normal semantics of flock
may require you to open the filehandle in write mode, say,
open $fh, '>>', $0;
open $fh, '+<', $0;
(From perldoc -f flock
)
Note that the fcntl(2) emulation of flock(3) requires that FILEHANDLE be open with read intent to use LOCK_SH and requires that it be open with write intent to use LOCK_EX.
File locking can fail for various reasons (for example if the file is on a network file system like NFS).
My solution is to create a directory while the script runs. Creating directories is always an atomic operation.
精彩评论