Mercurial > pub > ImplabNet
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 |