1 """Mutual exclusion -- for use with module sched 2 3 A mutex has two pieces of state -- a 'locked' bit and a queue. 4 When the mutex is not locked, the queue is empty. 5 Otherwise, the queue contains 0 or more (function, argument) pairs 6 representing functions (or methods) waiting to acquire the lock. 7 When the mutex is unlocked while the queue is not empty, 8 the first queue entry is removed and its function(argument) pair called, 9 implying it now has the lock. 10 11 Of course, no multi-threading is implied -- hence the funny interface 12 for lock, where a function is called once the lock is aquired. 13 """ 14 from warnings import warnpy3k 15 warnpy3k("the mutex module has been removed in Python 3.0", stacklevel=2) 16 del warnpy3k 17 18 from collections import deque 19 20 class mutex: 21 def __init__(self): 22 """Create a new mutex -- initially unlocked.""" 23 self.locked = False 24 self.queue = deque() 25 26 def test(self): 27 """Test the locked bit of the mutex.""" 28 return self.locked 29 30 def testandset(self): 31 """Atomic test-and-set -- grab the lock if it is not set, 32 return True if it succeeded.""" 33 if not self.locked: 34 self.locked = True 35 return True 36 else: 37 return False 38 39 def lock(self, function, argument): 40 """Lock a mutex, call the function with supplied argument 41 when it is acquired. If the mutex is already locked, place 42 function and argument in the queue.""" 43 if self.testandset(): 44 function(argument) 45 else: 46 self.queue.append((function, argument)) 47 48 def unlock(self): 49 """Unlock a mutex. If the queue is not empty, call the next 50 function with its argument.""" 51 if self.queue: 52 function, argument = self.queue.popleft() 53 function(argument) 54 else: 55 self.locked = False 56