Jim Dukarm wrote:
> On Monday 23 August 2004 11:52, Graham Fawcett wrote:
>
>>I need to implement a lock in a certain block of code, so that only one
>>process at a time is will be able to execute the restricted block. (Note
>>this is an inter-process lock, not an inter-thread lock, or I would just
>>use the standard threading library.)
>>
>
> Would it be practical to run the restricted code in its own process as a
> server (maybe using Medusa or sockets) which responds to only one request
> from your application(s) at a time? That would be a very portable solution.
Why didn't I think of that? Actually, moving the code into Medusa would
be a pain. But I could write a server to manage semaphores, upon which I
could build the locks. In fact, it could even be multithreaded...
.... ...
Okay, this ought to do the trick. Thanks for the inspiration, Jim!
-- Graham
# =====================================================
"""
ipc_lock.py: lightweight interprocess locks.
Usage:
from ipc_lock import Lock
lock = Lock('lock_name')
lock.acquire()
try:
do_something()
finally:
lock.release()
You must run a lock server as well:
ls = LockServer()
ls.serve_forever()
will do the trick.
It's a basic socket server, multi-threaded, with a basic line protocol.
Commands are of the form
:= '\n'
:= '+' | '-' | '*'
:= [^\n]*
where is a single character command in '+-*'. The message '+fred'
would acquire the lock named 'fred', blocking until it's available.
'-fred' will release the lock. The dangerous '*' command will release
all locks and is for debugging.
"""
from threading import Lock as _Lock
import socket
import SocketServer
class LockServer(SocketServer.ThreadingTCPServer):
PORT = 5555
locks = {}
def __init__(self):
SocketServer.ThreadingTCPServer.__init__(
self,
('', self.PORT),
LockHandler)
print 'serving %s on port %d' % (self, self.PORT)
def get_lock(self, lockname):
if not self.locks.has_key(lockname):
self.locks[lockname] = _Lock()
return self.locks[lockname]
class LockHandler(SocketServer.BaseRequestHandler):
def handle(self):
data = ''
while not '\n' in data:
data += self.request.recv(128)
data = data.rstrip()
cmd = data[0]
if cmd == '*':
self.server.locks.clear()
self.request.send('*\r\n')
else:
key = data[1:]
lock = self.server.get_lock(key)
if cmd == '+':
lock.acquire()
self.request.send('+%s\r\n' % key)
elif cmd == '-':
lock.release()
self.request.send('-%s\r\n' % key)
else:
self.request.send('?%s' % data)
class Lock:
def __init__(self, name):
self.name = name
def acquire(self):
s = socket.socket()
s.connect(('localhost', 5555))
s.send('+%s\n' % self.name)
return s.recv(1024)
# okay, I copy-pasted. Sue me...
def release(self):
s = socket.socket()
s.connect(('localhost', 5555))
s.send('-%s\n' % self.name)
return s.recv(1024)
def clear_all():
s = socket.socket()
s.connect(('localhost', 5555))
s.send('*\n')
return s.recv(1024)
if __name__ == '__main__':
s = LockServer()
s.serve_forever()