annotate Implab/Parallels/SharedLock.cs @ 196:40d7fed4a09e

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