Ras has asked for the wisdom of the Perl Monks concerning the following question:

I need help again. I don't if this is allowed in perl but is it possible to lock a currnet program you are in? Meaning, i have this program called program.pl, when program.pl executes i want to lock program.pl so no else can kick off program.pl. Before program.pl finishes i want to unlock program.pl. (is it possible to show me some syntax?). Many thanks to the one who can help me.

Replies are listed 'Best First'.
Re: Locking files
by Hofmator (Curate) on Aug 10, 2001 at 16:43 UTC

    If I understand you correctly, you want to allow only one invocation of you script running at the same time. If this is the case, then take a look at Highlander - there can be only one!!

    -- Hofmator

Re: Locking files
by trantor (Chaplain) on Aug 10, 2001 at 17:05 UTC

    In general, it's advisable to lock the resources your program is working on, not the program itself. Think about the consequencies in case of abnormal termination and so on.

    Anyway, There's More Than One Way To Do It. The most straightforward is probably using a wrapper, that is, a pprogram that does some housekeeping before calling the actual one.

    I'd suggest a wrapper and not changing yuor program itself because changing the program for adding this "feature" needs to be seriously motivated, in my opinion. Again, I think that locking resources is a cleaner approach.

    Unfornutately you can't use perl's flock because it requires a file to be open in write mode for having an exclusive lock, and production scripts that can be open in write mode are not a Good Thing.

    So you may resort to a couple of quite common tricks (watch out, ythey're not immune from race conditions! But most programmers seem not to care too much about it):

    • When the wrapper starts, it checks the process table and does an exec of the actual program only if not already in the process table. Very easily accomplished by a shell script. Not very portable: some systems (I assume UNIX) want you to type ps auwx, some others ps -ef.
    • When the wrapper starts, it checks for the presence of a file, say /var/run/program_is_running. If the file is not there, it is immediately created and the actual process is spawned. When it finishes, the wrapper regains control and gets rid of /var/run/program_is_running

    Both approaches can be implemented with simple shell scripts, valid in general for every program to be run in "exclusive" mode. As a side note, this kind of locking is only advisory! Malicious programs can circumvent it if they want.

    If you want to change your code, you can use Perl's flock in a number of ways, always locking a dummy file, not the program itself!

    For example (untested code):

    #!/usr/bin/perl -w use strict; open(EXCLUSIVELOCK, ">/tmp/$0.lock"); flock(EXCLUSIVELOCK, LOCK_EX); # If we reach this point, we have exclusive lock # The rest of the code goes here, immediately before # terminating, you can release the lock flock(EXCLUSIVELOCK, LOCK_UN);

    This type of locking is always advisory, but it's exempt from race conditions.

    This should be a good starting point to modify according to youir needs, for example not timeouts are implemented: if the file is locked, a second program would wait until the first has finished. You may want to check the perlfunc manual page to give an error and exit instead, or implement timeouts and so on. Happy locking!

    -- TMTOWTDI

      About your "Unfortunately" note. Not necessarily true.

      Perl's flock is only able to do exclusive locking on files opened for write if your system lacks both a native flock and a native fcntl. There is an excellent chance that a *nix like OS has flock.

      BUT BEWARE! On some operating systems you may have flock but it won't always work (eg Linux fails on NFS mounted partitions). The presence of this failure condition is non-obvious, and furthermore failure to lock tends to be missed in light testing, even though it is often critical in production. For that reason it is extremely important to always test whether flock succeeded and handle errors sanely (eg through a die).

Re: Locking files
by claree0 (Hermit) on Aug 10, 2001 at 16:45 UTC
    My first instinct would to have the first thing program.pl does be check the process list for number of instances of that prog, and exit if more than one....then you don't need to lock/unlock (and I can't think of a way to do that), just exit early.
    Clare
      I don't understand what you mean claree0. Can you show me some kind of example. thanks.
        Ras,

        Assuming that you are doing this on some sort of unix-like OS, then grepping the output of `ps ax | grep program.pl | wc -l` ought to give you the current number of running processes from that program. If 1 then it is the only instance. If 2 then another is already running, and you can exit the new instance.

        There may be a better way of doing this without making calls outside perl - I still talk 'perl baby-talk' quite a lot!

        Clare