Search code examples
pythonfcntl

Python fcntl does not lock as expected


On a Debian-based OS (Ubuntu, Debian Squeeze), I'm using Python (2.7, 3.2) fcntl to lock a file. As I understand from what I read, fnctl.flock locks a file in a way, that an exception will be thrown if another client wants to lock the same file.

I built a little example, which I would expect to throw an excepiton, since I first lock the file, and then, immediately after, I try to lock it again:

#!/usr/bin/env python
# -*- coding: utf-8 -*-
import fcntl
fcntl.flock(open('/tmp/locktest', 'r'), fcntl.LOCK_EX)
try:
    fcntl.flock(open('/tmp/locktest', 'r'), fcntl.LOCK_EX | fcntl.LOCK_NB)
except IOError:
    print("can't immediately write-lock the file ($!), blocking ...")
else:
    print("No error")

But the example just prints "No error".

If I split this code up to two clients running at the same time (one locking and then waiting, the other trying to lock after the first lock is already active), I get the same behavior - no effect at all.

Whats the explanation for this behavior?

EDIT:

Changes as requested by nightcracker, this version also prints "No error", although I would not expect that:

#!/usr/bin/env python
# -*- coding: utf-8 -*-
import fcntl
import time
fcntl.flock(open('/tmp/locktest', 'w'), fcntl.LOCK_EX | fcntl.LOCK_NB)
try:
    fcntl.flock(open('/tmp/locktest', 'w'), fcntl.LOCK_EX | fcntl.LOCK_NB)
except IOError:
    print("can't immediately write-lock the file ($!), blocking ...")
else:
    print("No error")

Solution

  • Got it. The error in my script is that I create a new file descriptor on each call:

    fcntl.flock(open('/tmp/locktest', 'r'), fcntl.LOCK_EX | fcntl.LOCK_NB)
    (...)
    fcntl.flock(open('/tmp/locktest', 'r'), fcntl.LOCK_EX | fcntl.LOCK_NB)
    

    Instead, I have to assign the file object to a variable and than try to lock:

    f = open('/tmp/locktest', 'r')
    fcntl.flock(f, fcntl.LOCK_EX | fcntl.LOCK_NB)
    (...)
    fcntl.flock(f, fcntl.LOCK_EX | fcntl.LOCK_NB)
    

    Than I'm also getting the exception I wanted to see: IOError: [Errno 11] Resource temporarily unavailable. Now I have to think about in which cases it makes sense at all to use fcntl.