Follow-up: Win32/Posix file locking
Sheila King
sheila at spamcop.net
Wed Aug 29 19:31:38 EDT 2001
OK, to follow up the other two threads that I've recently started on the
topic of cross-platform file locking, I will share the code that I am
currently working with. I believe that I have solved my problem. I've
tested the code on both Win98 and Linux and it seems to work.
Ignacio suggested that I rename the module to something having to do
with Mutex objects, rather than file locking, and I have done so. The
idea is to acquire a lock on some Mutex before trying to write to a
datafile.
Here is the parent class:
-----------------------(begin MutexFile.py)--------------------------
'''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.
'''
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
-----------------------(end MutexFile.py)--------------------------
Below I present the two platform specific modules that implement the
file locking. I've used non-blocking locks with retries and time outs.
I've tried to handle a process crashing by coding a __del___ function
for the object. If anyone has feedback, I'm more than interested in
hearing it.
--
Sheila King
http://www.thinkspot.net/sheila/
http://www.k12groups.org/
----------------------(begin posixMutexFile.py)----------------------
''' posixMutexFile.py
class lockfile
supports the same function calls as
winLock.lockfile
export to LockFile.py: a wrapper module
around the win and posix mutexfiles
'''
import os, fcntl
from time import time
MAXTIME = 8 # number of secs to retry for a lock before timing out
class mutexfile:
def __init__(self, filename):
if os.access(filename, os.F_OK):
self.filename = filename
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
if hasattr(self, 'fd'):
del self.fd
def getReadLock(self):
start_time = time()
while time() - start_time < MAXTIME:
try:
self.f = open(self.filename, 'r')
self.fd = self.f.fileno()
fcntl.lockf(self.fd, fcntl.LOCK_SH | fcntl.LOCK_NB)
return 1
except:
self.f.close()
del self.fd
if not hasattr(self, 'fd'):
errmssg = self.filename + " temporarily unavailable"
raise IOError, errmssg
def getWriteLock(self):
start_time = time()
while time() - start_time < MAXTIME:
try:
self.f = open(self.filename, 'r+')
self.fd = self.f.fileno()
fcntl.lockf(self.fd, fcntl.LOCK_EX | fcntl.LOCK_NB)
return 1
except:
self.f.close()
del self.fd
if not hasattr(self, 'fd'):
errmssg = self.filename + " temporarily unavailable"
raise IOError, errmssg
def unlock(self):
fcntl.lockf(self.fd, fcntl.LOCK_UN)
self.f.close()
del self.fd
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
----------------------(end posixMutexFile.py)----------------------
----------------------(begin winMutexFile.py)----------------------
''' 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
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 ActiveState.com Python win32
extensions"
MAXTIME = 8 # number of secs to retry for a lock before timing out
class mutexfile:
def __init__(self, filename):
if os.access(filename, os.F_OK):
self.filename = filename
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
if hasattr(self, 'fd'):
del self.fd
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
if not hasattr(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
if not hasattr(self,'fd'):
errmssg = self.filename + " temporarily unavailable"
raise IOError, errmssg
def unlock(self):
win32file.CloseHandle(self.fd)
del self.fd
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
----------------------(end winMutexFile.py)----------------------
More information about the Python-list
mailing list