Project

General

Profile

Statistics
| Branch: | Revision:

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()