* * * * * my-programand you don't want to have the next instance run before the current instance has finished.
A lock file is an ordinary file. The program
flock is a simple facility, but it is sufficient for many applications.
use Fcntl qw(:DEFAULT :flock); sub Lock { my $lock = "/var/lock/my-application"; sysopen LOCK, $lock, O_CREAT or die "Can't sysopen $lock: $!"; flock LOCK, LOCK_EX or die "Can't flock $lock: $!"; }When you use flock, you have to make some implementation decisions.
my $dir = "/var/lock/my-application"; my $dir = "/var/lock/my-organization/my-application"; -d $dir or mkdir $dir or die "Can't mkdir $dir: $!\n"; my $lock = "$dir/my-resource"; ...The contents of the lockfile are irrelevant; lockfiles are typically empty.
flock LOCK, LOCK_EX | LOCK_NBThen flock will return true if it acquired the lock, and false if it did not. It is up to the caller to handle both cases appropriately.
flock LOCK, LOCK_UN or Die "Can't release flock on $lock: $!"; close LOCK;However, this is often unnecessary. A program only needs to release a lock if it wants to grant other programs access to the protected resource while the program that released the lock continues to run.
If a program needs exclusive access to the shared resource for the duration of its own execution, then it can simply acquire the lock and forget about it. When the program exits, the OS automatically releases all locks acquired by the program and closes all files opened by the program. Code that releases locks immediately before program exit is superfluous if it works correctly, and (obviously) bad if it doesn't.
Recommend best practice is for programs to only release locks if there is some performance benefit to be gained, for example, by allowing other programs access to shared resources sooner than they would otherwise have it. In particular, a program that wants to prevent more than one instance of itself from running at a time need not—and probably should not—release its own locks.
NEVER DO THIS
unlinking the lock file creates the very race conditions that flock is designed to prevent. Observe:
program | operation | result | notes |
---|---|---|---|
A | creates the lock file | ||
A | opens the lock file | ||
A | calls flock | acquires the lock | |
B | opens the lock file | ||
B | calls flock | blocks | |
A | releases the lock | ||
B | acquires the lock | ||
A | unlinks the lock file | BAD | |
C | creates a new lock file with the same name | ||
C | opens the new lock file | ||
C | calls flock | acquires a lock on the new lock file |
Programs B and C have now acquired locks on two different lock files. They are running at the same time against the shared resource, and are liable to corrupt it.
Note that the time window for this race to occur is substantial. All that is necessary is that program B call flock while program A holds the lock, and program C call flock while program B holds the lock. In practice, those two time intervals could be many seconds long.