comparison Implab/Parallels/SharedLock.cs @ 136:e9e7940c7d98 v2

shared locks + tests
author cin
date Mon, 16 Feb 2015 01:14:09 +0300
parents 671f60cd0250
children
comparison
equal deleted inserted replaced
135:656815cb7147 136:e9e7940c7d98
6 /// <summary> 6 /// <summary>
7 /// Implements a lightweight mechanism to aquire a shared or an exclusive lock. 7 /// Implements a lightweight mechanism to aquire a shared or an exclusive lock.
8 /// </summary> 8 /// </summary>
9 public class SharedLock { 9 public class SharedLock {
10 readonly object m_lock = new object(); 10 readonly object m_lock = new object();
11 // the count of locks currently acquired by clients
11 int m_locks; 12 int m_locks;
13 // the count of pending requests for upgrade
14 int m_upgrades;
12 bool m_exclusive; 15 bool m_exclusive;
13 16
14 public bool LockExclusive(int timeout) { 17 public bool LockExclusive(int timeout) {
15 lock (m_lock) { 18 lock (m_lock) {
16 if (m_locks > 0 && !Monitor.Wait(m_lock, timeout)) 19 var dt = timeout;
17 return false; 20 if (m_locks > m_upgrades) {
21 var t1 = Environment.TickCount;
22 do {
23 if (!Monitor.Wait(m_lock, timeout))
24 return false;
25
26 if (m_locks == m_upgrades)
27 break;
28
29 if (timeout > 0) {
30 dt = timeout - Environment.TickCount + t1;
31 if (dt < 0)
32 return false;
33 }
34 } while(true);
35 }
18 m_exclusive = true; 36 m_exclusive = true;
19 m_locks = 1; 37 m_locks ++;
20 return true; 38 return true;
21 } 39 }
22 } 40 }
23 41
24 public void LockExclusive() { 42 public void LockExclusive() {
25 LockExclusive(-1); 43 lock (m_lock) {
26 } 44
27 45 while (m_locks > m_upgrades)
46 Monitor.Wait(m_lock);
47
48 m_exclusive = true;
49 m_locks ++;
50 }
51 }
52
53 /// <summary>
54 /// Acquires a shared lock.
55 /// </summary>
56 /// <returns><c>true</c>, if the shared lock was acquired, <c>false</c> if the specified timeout was expired.</returns>
57 /// <param name="timeout">Timeout.</param>
28 public bool LockShared(int timeout) { 58 public bool LockShared(int timeout) {
29 lock (m_lock) { 59 lock (m_lock) {
30 if (!m_exclusive) { 60 if (!m_exclusive) {
31 m_locks++; 61 m_locks++;
32 return true; 62 return true;
33 } 63 }
34 64
35 if (m_locks == 0) { 65 if (m_locks == m_upgrades) {
36 m_exclusive = false; 66 m_exclusive = false;
37 m_locks = 1; 67 m_locks = 1;
38 return true; 68 return true;
39 } 69 }
40 70
41 if (Monitor.Wait(m_lock, timeout)) { 71 var t1 = Environment.TickCount;
42 Debug.Assert(m_locks == 0); 72 var dt = timeout;
43 m_locks = 1; 73 do {
74 if (!Monitor.Wait(m_lock, dt))
75 return false;
76
77 if (m_locks == m_upgrades || !m_exclusive)
78 break;
79
80 if (timeout >= 0) {
81 dt = timeout - Environment.TickCount + t1;
82 if (dt < 0)
83 return false;
84 }
85 } while(true);
86
87 m_locks ++;
88 m_exclusive = false;
89 return true;
90 }
91 }
92
93 /// <summary>
94 /// Acquires the shared lock.
95 /// </summary>
96 public void LockShared() {
97 lock (m_lock) {
98 if (!m_exclusive) {
99 m_locks++;
100 } else if (m_locks == m_upgrades) {
44 m_exclusive = false; 101 m_exclusive = false;
102 m_locks++;
103 } else {
104 while (m_exclusive && m_locks > m_upgrades)
105 Monitor.Wait(m_lock);
106
107 m_locks++;
108 m_exclusive = false;
109 }
110 }
111 }
112
113 /// <summary>
114 /// Upgrades the current lock to exclusive level.
115 /// </summary>
116 /// <remarks>If the current lock is exclusive already the method does nothing.</remarks>
117 public void Upgrade() {
118 lock (m_lock) {
119 if (!m_exclusive) {
120
121 if (m_locks <= m_upgrades)
122 throw new InvalidOperationException();
123
124 if (m_locks - m_upgrades == 1) {
125 m_exclusive = true;
126 } else {
127 m_upgrades++;
128
129 while (m_locks > m_upgrades)
130 Monitor.Wait(m_lock);
131
132 m_upgrades--;
133 m_exclusive = true;
134 }
135 }
136 }
137 }
138
139 /// <summary>
140 /// Upgrades the current lock to exclusive level.
141 /// </summary>
142 /// <param name="timeout">Timeout.</param>
143 /// <returns><c>true</c> if the current lock was updated, <c>false</c> the specified timeout was expired.</returns>
144 /// <remarks>If the current lock is exclusive already the method does nothing.</remarks>
145 public bool Upgrade(int timeout) {
146 lock (m_lock) {
147 if (m_exclusive)
45 return true; 148 return true;
46 } 149 if (m_locks <= m_upgrades)
47 return false;
48 }
49 }
50
51 public void LockShared() {
52 LockShared(-1);
53 }
54
55 public void ReleaseShared() {
56 lock (m_lock) {
57 if (m_exclusive || m_locks <= 0)
58 throw new InvalidOperationException(); 150 throw new InvalidOperationException();
59 m_locks--; 151
60 if (m_locks == 0) 152 if (m_locks - m_upgrades == 1) {
153 m_exclusive = true;
154 } else {
155 var t1 = Environment.TickCount;
156 var dt = timeout;
157 m_upgrades++;
158 do {
159 if (!Monitor.Wait(m_lock, dt)) {
160 m_upgrades--;
161 return false;
162 }
163
164 // we may get there but the shared lock already aquired
165 if (m_locks == m_upgrades)
166 break;
167
168 if (timeout >= 0) {
169 dt = timeout - Environment.TickCount + t1;
170 if (dt < 0) {
171 m_upgrades--;
172 return false;
173 }
174 }
175 } while(true);
176 m_upgrades--;
177 m_exclusive = true;
178 }
179 return true;
180 }
181 }
182
183 /// <summary>
184 /// Downgrades this lock to shared level.
185 /// </summary>
186 public void Downgrade() {
187 lock (m_lock)
188 m_exclusive = false;
189 }
190
191 /// <summary>
192 /// Releases the current lock.
193 /// </summary>
194 public void Release() {
195 lock (m_lock)
196 // if no more running threads left
197 if (--m_locks == m_upgrades)
61 Monitor.PulseAll(m_lock); 198 Monitor.PulseAll(m_lock);
62 } 199 }
63 }
64
65 public void ReleaseExclusive() {
66 lock (m_lock) {
67 if (!m_exclusive && m_locks != 1)
68 throw new InvalidOperationException();
69 m_locks = 0;
70 Monitor.PulseAll(m_lock);
71 }
72 }
73
74 } 200 }
75 } 201 }
76 202