1 | """
|
---|
2 |
|
---|
3 | Synchronization primitives:
|
---|
4 |
|
---|
5 | - reader-writer lock (preference to writers)
|
---|
6 |
|
---|
7 | """
|
---|
8 |
|
---|
9 | import threading
|
---|
10 |
|
---|
11 | class RWLock:
|
---|
12 | """
|
---|
13 | Classic implementation of reader-writer lock with preference to writers.
|
---|
14 |
|
---|
15 | Readers can access a resource simultaneously.
|
---|
16 | Writers get an exclusive access.
|
---|
17 |
|
---|
18 | API is self-descriptive:
|
---|
19 | reader_enters()
|
---|
20 | reader_leaves()
|
---|
21 | writer_enters()
|
---|
22 | writer_leaves()
|
---|
23 | """
|
---|
24 |
|
---|
25 | def __init__(self):
|
---|
26 | self.mutex = threading.RLock()
|
---|
27 | self.can_read = threading.Semaphore(0)
|
---|
28 | self.can_write = threading.Semaphore(0)
|
---|
29 | self.active_readers = 0
|
---|
30 | self.active_writers = 0
|
---|
31 | self.waiting_readers = 0
|
---|
32 | self.waiting_writers = 0
|
---|
33 |
|
---|
34 | def reader_enters(self):
|
---|
35 | self.mutex.acquire()
|
---|
36 | try:
|
---|
37 | if self.active_writers == 0 and self.waiting_writers == 0:
|
---|
38 | self.active_readers += 1
|
---|
39 | self.can_read.release()
|
---|
40 | else:
|
---|
41 | self.waiting_readers += 1
|
---|
42 | finally:
|
---|
43 | self.mutex.release()
|
---|
44 | self.can_read.acquire()
|
---|
45 |
|
---|
46 | def reader_leaves(self):
|
---|
47 | self.mutex.acquire()
|
---|
48 | try:
|
---|
49 | self.active_readers -= 1
|
---|
50 | if self.active_readers == 0 and self.waiting_writers != 0:
|
---|
51 | self.active_writers += 1
|
---|
52 | self.waiting_writers -= 1
|
---|
53 | self.can_write.release()
|
---|
54 | finally:
|
---|
55 | self.mutex.release()
|
---|
56 |
|
---|
57 | def writer_enters(self):
|
---|
58 | self.mutex.acquire()
|
---|
59 | try:
|
---|
60 | if self.active_writers == 0 and self.waiting_writers == 0 and self.active_readers == 0:
|
---|
61 | self.active_writers += 1
|
---|
62 | self.can_write.release()
|
---|
63 | else:
|
---|
64 | self.waiting_writers += 1
|
---|
65 | finally:
|
---|
66 | self.mutex.release()
|
---|
67 | self.can_write.acquire()
|
---|
68 |
|
---|
69 | def writer_leaves(self):
|
---|
70 | self.mutex.acquire()
|
---|
71 | try:
|
---|
72 | self.active_writers -= 1
|
---|
73 | if self.waiting_writers != 0:
|
---|
74 | self.active_writers += 1
|
---|
75 | self.waiting_writers -= 1
|
---|
76 | self.can_write.release()
|
---|
77 | elif self.waiting_readers != 0:
|
---|
78 | t = self.waiting_readers
|
---|
79 | self.waiting_readers = 0
|
---|
80 | self.active_readers += t
|
---|
81 | while t > 0:
|
---|
82 | self.can_read.release()
|
---|
83 | t -= 1
|
---|
84 | finally:
|
---|
85 | self.mutex.release()
|
---|