A workmate asked me the best way to ensure that only one copy
of his Perl script is running at a time. From a quick SuperSearch,
a couple caught my eye:
I was intrigued by the adamk trick, so tested it with:
use strict;
use warnings;
use Fcntl qw(:flock);
print "start of program\n";
unless (flock(DATA, LOCK_EX|LOCK_NB)) {
print "$0 is already running. Exiting.\n";
exit(1);
}
print "sleeping 15...\n";
sleep(15);
print "end of program\n";
__DATA__
This exists so flock() code above works.
DO NOT REMOVE THIS DATA SECTION.
This works fine on Unix. On Windows, however, instead
of exiting with a nice "already running" message, the perl
script surprised me by printing nothing and exiting
immediately with an exit code of zero (this is the same perplexing
behaviour reported by
BrowserUk in
Re: Why no LockFile() in Win32API::File ?).
Stepping through the code in the debugger reveals the root cause
of this odd behaviour. When the file is locked on Windows, you can
open it ok but you get an error when you attempt to read from it.
Now, the lower layers of the Perl IO system detect the read error
all right (setting PerlIOBase(f)->flags |= PERLIO_F_ERROR), but
the first PerlIO_getc() call in Perl_sv_gets() returns EOF ... so perl
dutifully parses and runs an empty file, which explains why
nothing happens and you get an exit code of zero.
So, being pressed for time, I suggested this variation on adamk's cute trick:
use strict;
use warnings;
use Fcntl qw(:flock);
my $lockfile = 'mylockfile';
sub BailOut {
print "$0 is already running. Exiting.\n";
print "(File '$lockfile' is locked).\n";
exit(1);
}
print "start of program\n";
open(my $fhpid, '>', $lockfile) or die "error: open '$lockfile': $!";
flock($fhpid, LOCK_EX|LOCK_NB) or BailOut();
print "sleeping 15...\n";
sleep(15);
print "end of program\n";
# Note: lock should be automatically released at end of program,
# no matter how the process is terminated.
Though this simple solution seems sound to me, it is easy to overlook
subtle problems and race conditions. So if anyone can see a flaw in
this solution or has any other advice, please respond away.