|
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 = 0 |
|
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 = 1 |
|
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 = 0 |