root / env / lib / python2.7 / site-packages / django / utils / synch.py @ 1a305335
History | View | Annotate | Download (2.61 KB)
1 | 1a305335 | officers | """
|
---|---|---|---|
2 | Synchronization primitives:
|
||
3 |
|
||
4 | - reader-writer lock (preference to writers)
|
||
5 |
|
||
6 | (Contributed to Django by eugene@lazutkin.com)
|
||
7 | """
|
||
8 | |||
9 | from __future__ import with_statement |
||
10 | |||
11 | import contextlib |
||
12 | try:
|
||
13 | import threading |
||
14 | except ImportError: |
||
15 | import dummy_threading as threading |
||
16 | |||
17 | |||
18 | class RWLock(object): |
||
19 | """
|
||
20 | Classic implementation of reader-writer lock with preference to writers.
|
||
21 |
|
||
22 | Readers can access a resource simultaneously.
|
||
23 | Writers get an exclusive access.
|
||
24 |
|
||
25 | API is self-descriptive:
|
||
26 | reader_enters()
|
||
27 | reader_leaves()
|
||
28 | writer_enters()
|
||
29 | writer_leaves()
|
||
30 | """
|
||
31 | def __init__(self): |
||
32 | self.mutex = threading.RLock()
|
||
33 | self.can_read = threading.Semaphore(0) |
||
34 | self.can_write = threading.Semaphore(0) |
||
35 | self.active_readers = 0 |
||
36 | self.active_writers = 0 |
||
37 | self.waiting_readers = 0 |
||
38 | self.waiting_writers = 0 |
||
39 | |||
40 | def reader_enters(self): |
||
41 | with self.mutex: |
||
42 | if self.active_writers == 0 and self.waiting_writers == 0: |
||
43 | self.active_readers += 1 |
||
44 | self.can_read.release()
|
||
45 | else:
|
||
46 | self.waiting_readers += 1 |
||
47 | self.can_read.acquire()
|
||
48 | |||
49 | def reader_leaves(self): |
||
50 | with self.mutex: |
||
51 | self.active_readers -= 1 |
||
52 | if self.active_readers == 0 and self.waiting_writers != 0: |
||
53 | self.active_writers += 1 |
||
54 | self.waiting_writers -= 1 |
||
55 | self.can_write.release()
|
||
56 | |||
57 | @contextlib.contextmanager
|
||
58 | def reader(self): |
||
59 | self.reader_enters()
|
||
60 | try:
|
||
61 | yield
|
||
62 | finally:
|
||
63 | self.reader_leaves()
|
||
64 | |||
65 | def writer_enters(self): |
||
66 | with self.mutex: |
||
67 | if self.active_writers == 0 and self.waiting_writers == 0 and self.active_readers == 0: |
||
68 | self.active_writers += 1 |
||
69 | self.can_write.release()
|
||
70 | else:
|
||
71 | self.waiting_writers += 1 |
||
72 | self.can_write.acquire()
|
||
73 | |||
74 | def writer_leaves(self): |
||
75 | with self.mutex: |
||
76 | self.active_writers -= 1 |
||
77 | if self.waiting_writers != 0: |
||
78 | self.active_writers += 1 |
||
79 | self.waiting_writers -= 1 |
||
80 | self.can_write.release()
|
||
81 | elif self.waiting_readers != 0: |
||
82 | t = self.waiting_readers
|
||
83 | self.waiting_readers = 0 |
||
84 | self.active_readers += t
|
||
85 | while t > 0: |
||
86 | self.can_read.release()
|
||
87 | t -= 1
|
||
88 | |||
89 | @contextlib.contextmanager
|
||
90 | def writer(self): |
||
91 | self.writer_enters()
|
||
92 | try:
|
||
93 | yield
|
||
94 | finally:
|
||
95 | self.writer_leaves() |