Welcome, guest | Sign In | My Account | Store | Cart

Since the year dot, file locking has been used as a very simple synchronizing primitive between processes. Here's my take on the approach. To try it, simply start two command windows/terminal windows and run the script in each.

Tested on WinXP and Ubuntu (Dapper and Feisty).

Python, 43 lines
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
import os

class FileLock:
    def __init__(self, filename):
        self.filename = filename
        self.fd = None
        self.pid = os.getpid()

    def acquire(self):
        try:
            self.fd = os.open(self.filename, os.O_CREAT|os.O_EXCL|os.O_RDWR)
            # Only needed to let readers know who's locked the file
            os.write(self.fd, "%d" % self.pid)
            return 1    # return ints so this can be used in older Pythons
        except OSError:
            self.fd = None
            return 0

    def release(self):
        if not self.fd:
            return 0
        try:
            os.close(self.fd)
            os.remove(self.filename)
            return 1
        except OSError:
            return 0

    def __del__(self):
        self.release()

def main():
    lock = FileLock("lock.file")
    while 1:
        if lock.acquire():
            raw_input("acquired lock. Press ENTER to release:")
            lock.release()
            raw_input("released lock. Press ENTER to retry:")
        else:
            raw_input("Unable to acquire lock. Press ENTER to retry:")

if __name__ == "__main__":
    main()

1 comment

David Eisner 10 years ago  # | flag

Thanks for this code. I did run into one issue: when exiting the interpreter after acquiring and releasing a lock, I'd get this error:

Exception AttributeError: AttributeError("'NoneType' object has no attribute 'close'",) in <bound method FileLock.__del__ of <FileLock.FileLock instance at 0x82bd0cc>> ignored

(I only saw this when importing a module that used FileLock, not when importing FileLock directly)

This patch fixes it by adding one line to the release() method:

--- FileLock_orig.py    2011-11-11 15:39:54.181276332 -0500
+++ FileLock_new.py     2011-11-11 15:40:16.061558054 -0500
@@ -22,6 +22,7 @@
         try:
             os.close(self.fd)
             os.remove(self.filename)
+            self.fd = None
             return 1
         except OSError:
             return 0
Created by Vinay Sajip on Wed, 9 May 2007 (PSF)
Python recipes (4591)
Vinay Sajip's recipes (2)

Required Modules

Other Information and Tasks