Mercurial > pub > ImplabNet
annotate Implab/Parallels/SharedLock.cs @ 137:238e15580926 v2
added the blocking queue
author | cin |
---|---|
date | Mon, 16 Feb 2015 17:48:39 +0300 |
parents | e9e7940c7d98 |
children |
rev | line source |
---|---|
129 | 1 using System; |
2 using System.Threading; | |
3 using System.Diagnostics; | |
4 | |
5 namespace Implab.Parallels { | |
6 /// <summary> | |
7 /// Implements a lightweight mechanism to aquire a shared or an exclusive lock. | |
8 /// </summary> | |
9 public class SharedLock { | |
10 readonly object m_lock = new object(); | |
136 | 11 // the count of locks currently acquired by clients |
129 | 12 int m_locks; |
136 | 13 // the count of pending requests for upgrade |
14 int m_upgrades; | |
129 | 15 bool m_exclusive; |
16 | |
17 public bool LockExclusive(int timeout) { | |
18 lock (m_lock) { | |
136 | 19 var dt = timeout; |
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 } | |
129 | 36 m_exclusive = true; |
136 | 37 m_locks ++; |
130
671f60cd0250
fixed Resove method bug when calling it on already cancelled promise
cin
parents:
129
diff
changeset
|
38 return true; |
129 | 39 } |
40 } | |
41 | |
42 public void LockExclusive() { | |
136 | 43 lock (m_lock) { |
44 | |
45 while (m_locks > m_upgrades) | |
46 Monitor.Wait(m_lock); | |
47 | |
48 m_exclusive = true; | |
49 m_locks ++; | |
50 } | |
129 | 51 } |
52 | |
136 | 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> | |
129 | 58 public bool LockShared(int timeout) { |
59 lock (m_lock) { | |
60 if (!m_exclusive) { | |
61 m_locks++; | |
62 return true; | |
63 } | |
64 | |
136 | 65 if (m_locks == m_upgrades) { |
129 | 66 m_exclusive = false; |
67 m_locks = 1; | |
68 return true; | |
69 } | |
136 | 70 |
71 var t1 = Environment.TickCount; | |
72 var dt = timeout; | |
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) { | |
129 | 101 m_exclusive = false; |
136 | 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; | |
129 | 109 } |
110 } | |
111 } | |
112 | |
136 | 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() { | |
129 | 118 lock (m_lock) { |
136 | 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 } | |
129 | 136 } |
137 } | |
138 | |
136 | 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) { | |
129 | 146 lock (m_lock) { |
136 | 147 if (m_exclusive) |
148 return true; | |
149 if (m_locks <= m_upgrades) | |
129 | 150 throw new InvalidOperationException(); |
136 | 151 |
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; | |
129 | 180 } |
181 } | |
182 | |
136 | 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) | |
198 Monitor.PulseAll(m_lock); | |
199 } | |
129 | 200 } |
201 } | |
202 |