On Thu, 10 Jan 2002 10:00:50 +0000 (GMT), Richard Smith wrote:

>I use an indirect method for locking files, which works fine on all platforms.
>I borrowed the method from a Matthew Wright script

Uh-oh...

>(tweaked a bit for my own
>taste in Perl style). The subroutines are as follows:
>
>sub lockFile    {
>        #       Create a lock file for the file passed as a parameter.
>        #       If no parameter is passed, return a false value.
>        $_ = shift or return 0;

No local()?

>        $_ = $_ . '.lock';
>        my $i;
>
>        for ($i = 0; $i < $timeOut; $i++) {
>        
>                (-e $_)
>                 and sleep 1
>                 and next;
>                 
>                 open LOCK, ">$_" or &outputError("Can't create lock file",
>$!);

That's what I thought. You've got a race condition. ANother program
might create the lockfile between your "the file does not exist" test,
and your "I'll make it now".

>                 print LOCK '0';
>                 close LOCK;
>                 last;
>        
>        }

There are better ways, to avoid the race condition. You can use
sysopen(), which allows for more ways to create a file than the plain
">" and ">>" modes: such as the O_EXCL (flag) mode You need some
constants from Fcntl.

And sleeping in increments of 1 second is far too course. Either use a
shorter sleep from Time::HiRes, or you could use the 4 argument select()
to  produce the time-out.

You also need to delete the lockfile when you're through. That's
dangerous: if your script dies, the lockfile won't be deleted. Unless
you take care of that...

Here's a draft, I haven't thoroughly tested it.

        use Fcntl;
        {
            my @lockfiles;
            END {
                foreach(@lockfiles) { unlink }  # for 5.004
            }
            sub lockFile ($) {
            #Create a lock file for the file passed as a parameter.
                my $lockfile = shift() . '.lock';
                my $t0 = time;
                local *LOCK;
                until(sysopen LOCK, $lockfile,
                  O_CREAT|O_TRUNC|O_EXCL|O_WRONLY) {
                    die "Too many loops" if time-$t0 > 10;
                    select undef, undef, undef, 0.1;
                }
                push @lockfiles, $lockfile;
                print LOCK $$;
                close LOCK;
            }
        }

-- 
        Bart.

Reply via email to