demerphq has asked for the wisdom of the Perl Monks concerning the following question:
I have some code that manages a lockfile mechanism used to keep various processes from working on the same things at once. The basic idea is that before a process starts a task it tries to get a lock on the task id. If it cant get the lock it tries to work on something else. What i wanted to do was to have it work like this:
But what happens is that unless I add a step 5.5 which is "Unlock the file" before we "Lock the file in shared mode" the lock status doesnt change from LOCK_EX to LOCK_SH. Thus other process sit waiting for ever. If I do put in the LOCK_UN step then it seems to work, but I cant help but feel there is a race condition involved if I do.
Anyway the code is below (Thanks to tilly for the OnDestroy trick or at least the idea that underlies it.)
use Fcntl ':flock'; use POSIX; sub iso_time { POSIX::strftime ("%Y-%m-%d %H:%M:%S",localtime($_[0]||t +ime)) } sub OnDestroy::DESTROY { shift(@_)->() } sub OnDestroyDo(&) { bless shift(@_),"OnDestroy" } sub get_lock { my ($lock_dir,$name)=@_; my $debug=1; $name=~s/[^-\w.#!\@~=+%\$]//g; my $lockfile=catfile($lock_dir,$name.'.lock'); print "Trying lockfile $lockfile\n"; sysopen(my $FH, $lockfile, O_RDWR | O_CREAT) or do { warn "can't open $lockfile: $!" if $debug; return; }; # autoflush $FH select( (select($FH), $|++)[0] ); my ( $time, $process, $lname ); if (flock( $FH, LOCK_EX | LOCK_NB )) { ( $time, $process, $lname )=split /\|/,join "",<$FH>; seek $FH, 0, 0 or die "Failed rewind:$!"; if ($debug) { if ($process) { print "\tLockfile appears to be abandonded by Process +#$process started at $time\n" } else { print "\tLockfile appears to be unprocessed\n" } } my $lock_msg=join("|", iso_time(), $$, $name)."\n"; print "Locking $lockfile : $lock_msg"; print $FH $lock_msg; truncate($FH, tell($FH)) or die "Failed to truncate:$!"; # if I remove this it doesnt work on my Win2k box flock($FH, LOCK_UN) or die "sharedlock: $!"; # but if I leave it in then it seems like a race condition is +possible. flock($FH, LOCK_SH|LOCK_NB) or die "sharedlock: $!"; return OnDestroyDo { print "\tFinished with and removing $lockf +ile\n"; close $FH or die "Failed to close \$FH:$!" +; unlink $lockfile or die "Failed to unlink +$lockfile\n"; undef $FH; }; } elsif (flock($FH, LOCK_SH|LOCK_NB)) { ( $time, $process, $lname )=split /\|/,join "",<$FH>; print "\tLockfile $lockfile appears to be locked by Process #$ +process at $time\n" if $debug; } else { print "Failed to get lock on $lockfile, not sure why.\n"; } return }
Thanks in advance for any help you might be able to offer.
First they ignore you, then they laugh at you, then they fight you, then you win.
-- Gandhi
|
|---|
| Replies are listed 'Best First'. | |
|---|---|
|
Re: Frustration with changing lock type
by hv (Prior) on Apr 14, 2004 at 11:30 UTC | |
by demerphq (Chancellor) on Apr 14, 2004 at 12:37 UTC | |
by hv (Prior) on Apr 14, 2004 at 12:47 UTC | |
by demerphq (Chancellor) on Apr 14, 2004 at 12:53 UTC | |
by hv (Prior) on Apr 14, 2004 at 13:02 UTC | |
by tye (Sage) on Apr 14, 2004 at 15:11 UTC | |
|
Re: Frustration with changing lock type
by crabbdean (Pilgrim) on Apr 14, 2004 at 12:20 UTC | |
by demerphq (Chancellor) on Apr 14, 2004 at 12:45 UTC | |
|
Re: Frustration with changing lock type
by tachyon (Chancellor) on Apr 14, 2004 at 11:26 UTC | |
by demerphq (Chancellor) on Apr 14, 2004 at 11:47 UTC |