How to lock files (the easiest/best way)?

Jim Segrave jes at nl.demon.net
Sun Jul 16 18:00:50 EDT 2006


In article <mailman.8240.1153081715.27775.python-list at python.org>,
Eric S. Johansson <esj at harvee.org> wrote:
>Elmo Mäntynen wrote:
>> Is there something better than using fnctl? It seems a bit intimidating
>> with a quick look.
>
>try the portlocker wrapper from the active state cookbook.  I have a 
>version which has been slightly updated for more modern pythons.  I 
>really need to make my darcs repository visible so you could get it.
>
>Alternatively, you can try the makedir trick.  Creating directories are 
>atomic operations if it exists, you will get error message.  If it 
>doesn't, you will get a directory and thereby capture the lock.  You 
>delete the directory when you release the lock.
>
>crude but effective.  I used it in building a file based queue system. 
>You know, I really should learn how to build eggs because I have a whole 
>bunch of little pieces of software that would probably be useful to others.

Here's a more complete file locking scheme which uses a lockfile with
the O_CREAT and O_EXCL flags to make the creation atomic. If it gets
the lock, it writes its PID in readable form in the file. It also does
two other things:

If you know that no process should lock the file for more than a fixed
period of time, it will retry once/second as long as the lock file is
not older than that fixed period of time. If it is older, it will
report the problem, including the PID of the locking process and exit.

This caters for a process which has set the lock file and then
terminates without removing it (which can happen do to an application
or server crash).

------------------------------------------

import os
import errno
import sys
import time
import stat

# the maximum reasonable time for aprocesstobe
max_wait = 10

lockfile = "/tmp/mylock"

while True:
    try:
        fd = os.open(lockfile, os.O_EXCL | os.O_RDWR | os.O_CREAT)
        # we created the lockfile, so we're the owner
        break
    except OSError, e:
        if e.errno != errno.EEXIST:
            # should not occur
            raise

        try:
            # the lock file exists, try to stat it to get its age
            # and read it's contents to report the owner PID
            f = open(lockfile, "r")
            s = os.stat(lockfile)
        except OSError, e:
            if e.errno != errno.EEXIST:
                sys.exit("%s exists but stat() failed: %s" %
                         (lockfile, e.strerror))
            # we didn't create the lockfile, so it did exist, but it's
            # gone now. Just try again
            continue
        
        # we didn't create the lockfile and it's still there, check
        # its age
        now = int(time.time())
        if now - s[stat.ST_MTIME] > max_wait:
            pid = f.readline()
            sys.exit("%s has been locked for more than " \
                     "%d seconds (PID %s)" % (lockfile, max_wait,
                     pid))

        # it's not been locked too long, wait a while and retry
        f.close()
        time.sleep(1)        

# if we get here. we have the lockfile. Convert the os.open file
# descriptor into a Python file object and record our PID in it

f = os.fdopen(fd, "w")
f.write("%d\n" % os.getpid())
f.close()




-- 
Jim Segrave           (jes at jes-2.demon.nl)




More information about the Python-list mailing list