Mutex a file?

Sheila King usenet at thinkspot.net
Thu Feb 14 17:27:16 EST 2002


On Thu, 14 Feb 2002 16:12:51 -0500, "MDK" <mdk at mdk.com> wrote in comp.lang.python in
article <a4h98k$ao2f$1 at ID-98166.news.dfncis.de>:

> I have a file that is to be read to and written from by many Python scripts
> running at the same time.
> 
> Is there a way to put a Mutex on it so that the scripts wait their turn
> before tyring to open it?

This is a problem I worked on some time back. On most Unices, it is not 
hard to lock the file (which is what you need to do). I guess there are 
some problems if you are working across certain types of networks. On 
WinNT and Win2000 (and probably XP) there is also a great deal of control 
over files and file access. It's the Win9x where you loose a lot of this 
ability. I'm not sure what platform you are running on...if Windows, 
you might want to look in more detail at the win32all libraries from 
Mark Hammond.

Anyhow, here are some links to the discussion I initiated on this topic 
some time back. Read the threads. There are many useful comments.
http://groups.google.com/groups?as_umsgid=t7uqot8n8gjm03r2m03md8kfsjuauchqhu%404ax.com
http://groups.google.com/groups?as_umsgid=djsfotomogdeba70gp1cuogjbt5ii3chrb%404ax.com
http://groups.google.com/groups?as_umsgid=bo2ootg61vmposfvsg8gvrks6eqiuss940%404ax.com
http://mail.python.org/pipermail/tutor/2001-August/008366.html


Here is the module I wrote, and am using in a production environment 
on a Linux server for file locking. Advice given to me re: the 
Windows component of this modules is...well, that it wouldn't be 
recommended to use in a production environment. But who would run 
a production server on a Win98 machine anyhow? So, for me it let's 
me test my scripts on my home Windows machine and then upload it 
to my Linux server and expect the same results.

FWIW, I've pasted the code I'm currently running below my sig.

-- 
Sheila King
http://www.thinkspot.net/sheila/

"When introducing your puppy to an adult cat,
restrain the puppy, not the cat." -- Gwen Bailey,
_The Perfect Puppy: How to Raise a Well-behaved Dog_


'''MutexFile.py

wraps WinMutexFile.py and posixMutexFile.py to provide
a single interface for working with mutex files
across win32 and posix platforms.
Does not support fine-grained locking.
Recommended for getting a lock on a sentinel file
before trying to read/write data to a separate data file.

public interface:
obj = MutexFile.MutexFile('somefile.txt')
obj.flock(flag)

where flag is one of the following:
LOCK_SH - get a shared (or read) lock
LOCK_EX - get an exclusive (or write) lock
LOCK_UN - release a lock
'''
import os

if os.name == 'nt':
     from winMutexFile import mutexfile
elif os.name == 'posix':
     from posixMutexFile import mutexfile
else:
    raise ImportError, "MutexFile is not supported on your platform."


class MutexFile(mutexfile):
    pass



''' posixMutexFile.py

class lockfile
supports the same function calls as
winLock.lockfile
export to MutexFile.py: a wrapper module
around the win and posix lockfiles
'''

import os, fcntl

class mutexfile:
    def __init__(self, filename):
        if os.access(filename, os.F_OK):
            self.filename = filename
            self.fd = None
        else:
            errmssg = filename + " does not exist. Can't lock non-existent file."
            raise IOError, errmssg

    def __del__(self):
        try:
            self.unlock()
        except:
            pass
        try:
            self.f.close()
        except:
            pass

    def getReadLock(self):
        self.f = open(self.filename, 'r')
        self.fd = self.f.fileno()
        fcntl.lockf(self.fd, fcntl.LOCK_SH)


    def getWriteLock(self):
        self.f = open(self.filename, 'r+')
        self.fd = self.f.fileno()
        fcntl.lockf(self.fd, fcntl.LOCK_EX)


    def unlock(self):
        fcntl.lockf(self.fd, fcntl.LOCK_UN)
        self.f.close()
        self.fd = None

    def flock(self, flag):
        '''flags are:
        LOCK_UN - unlock
        LOCK_SH - acquire a shared (or read) lock
        LOCK_EX - acquire an exclusive (or write) lock
        '''
        if flag == 'LOCK_SH':
            self.getReadLock()
        elif flag == 'LOCK_EX':
            self.getWriteLock()
        elif flag == 'LOCK_UN':
            self.unlock()
        else:
            errmssg = "The flag " + flag + " is not implemented for flock"
            raise NotImplementedError, errmssg



''' winMutexFile.py

class lockfile
supports the same function calls as
posixLock.lockobject
export to lockobject.py: a wrapper module
around the win and posix lockobjects
'''
import os
from time import time, sleep

try:
    import win32file
    from win32con import GENERIC_READ, GENERIC_WRITE,\
        FILE_SHARE_READ, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL
except ImportError, e:
    print e
    print "winMutexFile.py requires the ActiveState.com Python win32 extensions"
    raise

MAXTIME = 8  # number of secs to retry for a lock before timing out
sleepinterval = 0.1 # number of secs to sleep between retries for lock

class mutexfile:
    def __init__(self, filename):
        if os.access(filename, os.F_OK):
            self.filename = filename
            self.fd = None
        else:
            errmssg = filename + " does not exist. Can't lock non-existent file."
            raise IOError, errmssg

    def __del__(self):
        try:
            self.unlock()
        except:
            pass
        try:
            self.f.close()
        except:
            pass

    def getReadLock(self):
        start_time = time()
        while time() - start_time < MAXTIME:
            try:
                self.fd = win32file.CreateFile(self.filename, GENERIC_READ,\
                                              FILE_SHARE_READ, None, OPEN_EXISTING,\
                                              FILE_ATTRIBUTE_NORMAL, 0)
                return 1
            except:
                pass
            sleep(sleepinterval)
        if not self.fd:
            errmssg = self.filename + " temporarily unavailable"
            raise IOError, errmssg

    def getWriteLock(self):
        start_time = time()
        while time() - start_time < MAXTIME:
            try:
                self.fd = win32file.CreateFile(self.filename, GENERIC_READ,\
                                              0, None, OPEN_EXISTING,\
                                              FILE_ATTRIBUTE_NORMAL, 0)
                return 1
            except:
                pass
            sleep(sleepinterval)
        if not self.fd:
            errmssg = self.filename + " temporarily unavailable"
            raise IOError, errmssg

    def unlock(self):
        win32file.CloseHandle(self.fd)
        self.fd = None

    def flock(self, flag):
        '''flags are:
        LOCK_UN - unlock
        LOCK_SH - acquire a shared (or read) lock
        LOCK_EX - acquire an exclusive (or write) lock
        '''
        if flag == 'LOCK_SH':
            self.getReadLock()
        elif flag == 'LOCK_EX':
            self.getWriteLock()
        elif flag == 'LOCK_UN':
            self.unlock()
        else:
            errmssg = "The flag " + flag + " is not implemented for flock"
            raise NotImplementedError, errmssg




More information about the Python-list mailing list