##// END OF EJS Templates
added memory barriers
cin -
r80:4f20870d0816 v2
parent child
Show More
@@ -0,0 +1,85
1 using System;
2 using Implab.Parallels;
3 using System.Threading;
4
5 namespace Implab {
6 /*public class SyncPool<T> : IDisposable {
7 readonly Func<T> m_factory;
8 readonly Action<T> m_cleanup;
9 readonly int m_size;
10 readonly MTQueue<T> m_queue = new MTQueue<T>();
11
12 volatile bool m_disposed;
13
14 volatile int m_count;
15
16 public SyncPool(Func<T> factory, Action<T> cleanup, int size) {
17 Safe.ArgumentNotNull(factory, "factory");
18 Safe.ArgumentInRange(size, 1, size, "size");
19
20 m_factory = factory;
21 m_cleanup = cleanup;
22 m_size = size;
23 }
24
25 public SyncPool(Func<T> factory, Action<T> cleanup) : this(factory,cleanup,Environment.ProcessorCount+1) {
26 }
27
28 public SyncPool(Func<T> factory) : this(factory,null,Environment.ProcessorCount+1) {
29 }
30
31 public SyncPoolWrapper<T> Allocate() {
32 if (m_disposed)
33 throw new ObjectDisposedException(this.ToString());
34
35 T instance;
36 if (m_queue.TryDequeue(out instance)) {
37 Interlocked.Decrement(ref m_count);
38 return instance;
39 } else {
40 instance = m_factory();
41 }
42 return new SyncPoolWrapper<T>(instance, this);
43 }
44
45 public void Release(T instance) {
46 if (m_count < m_size && !m_disposed) {
47 Interlocked.Increment(ref m_count);
48
49 if (m_cleanup != null)
50 m_cleanup(instance);
51
52 m_queue.Enqueue(instance);
53
54 // ΠΏΠΎΠΊΠ° элСмСнт возвращался Π² кСш, Π±Ρ‹Π»Π° Π½Π°Ρ‡Π°Ρ‚Π° опСрация освобоТдСния всСго кСша
55 // ΠΈ Π²ΠΎΠ·ΠΌΠΎΠΆΠ½ΠΎ ΡƒΠΆΠ΅ Π·Π°ΠΊΠΎΠ½Ρ†Π΅Π½Π°, Π² Ρ‚Π°ΠΊΠΎΠΌ случаС слСдуСт ΠΈΠ·Π²Π»Π΅Ρ‡ΡŒ элСмСнт ΠΎΠ±Ρ€Π°Ρ‚Π½ΠΎ ΠΈ
56 // ΠΎΡΠ²ΠΎΠ±ΠΎΠ΄ΠΈΡ‚ΡŒ Π΅Π³ΠΎ. Если опСрация освобоТдСния кСша Π΅Ρ‰Π΅ Π½Π΅ Π·Π°Π²Ρ€Π΅ΡˆΠΈΠ»Π°ΡΡŒ, Ρ‚ΠΎ Π±ΡƒΠ΄Π΅Ρ‚
57 // ΠΈΠ·ΡŠΡΡ‚ ΠΈ освобоТдСн ΠΏΡ€ΠΎΠΈΠ·Π²ΠΎΠ»ΡŒΠ½Ρ‹ΠΉ элСмСн, Ρ‡Ρ‚ΠΎ Π½Π΅ повлияСт Π½Π° Ρ…ΠΎΠ΄ всСго процСсса.
58 if (m_disposed && m_queue.TryDequeue(out instance))
59 Safe.Dispose(instance);
60
61 } else {
62 Safe.Dispose(instance);
63 }
64 }
65
66 protected virtual void Dispose(bool disposing) {
67 if (disposing) {
68 m_disposed = true;
69 T instance;
70 while (m_queue.TryDequeue(out instance))
71 Safe.Dispose(instance);
72 }
73 }
74
75 #region IDisposable implementation
76
77 public void Dispose() {
78 Dispose(true);
79 GC.SuppressFinalize(this);
80 }
81
82 #endregion
83 }*/
84 }
85
@@ -0,0 +1,24
1 using System;
2
3 namespace Implab {
4 /*public struct SyncPoolWrapper<T> : IDisposable {
5 readonly T m_value;
6 readonly SyncPool<T> m_pool;
7
8 internal SyncPoolWrapper(T value, SyncPool<T> pool) {
9 m_value = value;
10 m_pool = pool;
11 }
12
13 public T Value {
14 get { return m_value; }
15 }
16
17 #region IDisposable implementation
18 public void Dispose() {
19 m_pool.Release(m_value);
20 }
21 #endregion
22 }*/
23 }
24
@@ -1,434 +1,434
1 1 using System;
2 2 using System.Reflection;
3 3 using System.Threading;
4 4 using Implab.Parallels;
5 5
6 6 #if MONO
7 7
8 8 using NUnit.Framework;
9 9 using TestClassAttribute = NUnit.Framework.TestFixtureAttribute;
10 10 using TestMethod = NUnit.Framework.TestAttribute;
11 11
12 12 #else
13 13
14 14 using Microsoft.VisualStudio.TestTools.UnitTesting;
15 15
16 16 #endif
17 17
18 18 namespace Implab.Test {
19 19 [TestClass]
20 20 public class AsyncTests {
21 21 [TestMethod]
22 22 public void ResolveTest() {
23 23 int res = -1;
24 24 var p = new Promise<int>();
25 25 p.Then(x => res = x);
26 26 p.Resolve(100);
27 27
28 28 Assert.AreEqual(100, res);
29 29 }
30 30
31 31 [TestMethod]
32 32 public void RejectTest() {
33 33 int res = -1;
34 34 Exception err = null;
35 35
36 36 var p = new Promise<int>();
37 37 p.Then(
38 38 x => res = x,
39 39 e => {
40 40 err = e;
41 41 return -2;
42 42 }
43 43 );
44 44 p.Reject(new ApplicationException("error"));
45 45
46 46 Assert.AreEqual(res, -1);
47 47 Assert.AreEqual(err.Message, "error");
48 48
49 49 }
50 50
51 51 [TestMethod]
52 52 public void CancelExceptionTest() {
53 53 var p = new Promise<bool>();
54 54 p.Cancel();
55 55
56 56 var p2 = p.Cancelled(() => {
57 57 throw new ApplicationException("CANCELLED");
58 58 });
59 59
60 60 try {
61 61 p2.Join();
62 62 Assert.Fail();
63 63 } catch (ApplicationException err) {
64 64 Assert.AreEqual("CANCELLED", err.InnerException.Message);
65 65 }
66 66
67 67 }
68 68
69 69 [TestMethod]
70 70 public void ContinueOnCancelTest() {
71 71 var p = new Promise<bool>();
72 72 p.Cancel();
73 73
74 74 var p2 = p
75 75 .Cancelled(() => {
76 76 throw new ApplicationException("CANCELLED");
77 77 })
78 78 .Error(e => true);
79 79
80 80 Assert.AreEqual(true, p2.Join());
81 81 }
82 82
83 83 [TestMethod]
84 84 public void JoinSuccessTest() {
85 85 var p = new Promise<int>();
86 86 p.Resolve(100);
87 87 Assert.AreEqual(p.Join(), 100);
88 88 }
89 89
90 90 [TestMethod]
91 91 public void JoinFailTest() {
92 92 var p = new Promise<int>();
93 93 p.Reject(new ApplicationException("failed"));
94 94
95 95 try {
96 96 p.Join();
97 97 throw new ApplicationException("WRONG!");
98 98 } catch (TargetInvocationException err) {
99 99 Assert.AreEqual(err.InnerException.Message, "failed");
100 100 } catch {
101 101 Assert.Fail("Got wrong excaption");
102 102 }
103 103 }
104 104
105 105 [TestMethod]
106 106 public void MapTest() {
107 107 var p = new Promise<int>();
108 108
109 109 var p2 = p.Then(x => x.ToString());
110 110 p.Resolve(100);
111 111
112 112 Assert.AreEqual(p2.Join(), "100");
113 113 }
114 114
115 115 [TestMethod]
116 116 public void FixErrorTest() {
117 117 var p = new Promise<int>();
118 118
119 119 var p2 = p.Error(e => 101);
120 120
121 121 p.Reject(new Exception());
122 122
123 123 Assert.AreEqual(p2.Join(), 101);
124 124 }
125 125
126 126 [TestMethod]
127 127 public void ChainTest() {
128 128 var p1 = new Promise<int>();
129 129
130 130 var p3 = p1.Chain(x => {
131 131 var p2 = new Promise<string>();
132 132 p2.Resolve(x.ToString());
133 133 return p2;
134 134 });
135 135
136 136 p1.Resolve(100);
137 137
138 138 Assert.AreEqual(p3.Join(), "100");
139 139 }
140 140
141 141 [TestMethod]
142 142 public void PoolTest() {
143 143 var pid = Thread.CurrentThread.ManagedThreadId;
144 144 var p = AsyncPool.Invoke(() => Thread.CurrentThread.ManagedThreadId);
145 145
146 146 Assert.AreNotEqual(pid, p.Join());
147 147 }
148 148
149 149 [TestMethod]
150 150 public void WorkerPoolSizeTest() {
151 151 var pool = new WorkerPool(5, 10, 0);
152 152
153 153 Assert.AreEqual(5, pool.PoolSize);
154 154
155 155 pool.Invoke(() => { Thread.Sleep(100000000); return 10; });
156 156 pool.Invoke(() => { Thread.Sleep(100000000); return 10; });
157 157 pool.Invoke(() => { Thread.Sleep(100000000); return 10; });
158 158
159 159 Assert.AreEqual(5, pool.PoolSize);
160 160
161 161 for (int i = 0; i < 100; i++)
162 162 pool.Invoke(() => { Thread.Sleep(100000000); return 10; });
163 163 Thread.Sleep(200);
164 164 Assert.AreEqual(10, pool.PoolSize);
165 165
166 166 pool.Dispose();
167 167 }
168 168
169 169 [TestMethod]
170 170 public void WorkerPoolCorrectTest() {
171 171 var pool = new WorkerPool(0,1000,100);
172 172
173 173 const int iterations = 1000;
174 174 int pending = iterations;
175 175 var stop = new ManualResetEvent(false);
176 176
177 177 var count = 0;
178 178 for (int i = 0; i < iterations; i++) {
179 179 pool
180 180 .Invoke(() => 1)
181 181 .Then(x => Interlocked.Add(ref count, x))
182 182 .Then(x => Math.Log10(x))
183 183 .Anyway(() => {
184 184 Interlocked.Decrement(ref pending);
185 185 if (pending == 0)
186 186 stop.Set();
187 187 });
188 188 }
189 189
190 190 stop.WaitOne();
191 191
192 192 Assert.AreEqual(iterations, count);
193 193 Console.WriteLine("Max threads: {0}", pool.MaxRunningThreads);
194 194 pool.Dispose();
195 195
196 196 }
197 197
198 198 [TestMethod]
199 199 public void WorkerPoolDisposeTest() {
200 200 var pool = new WorkerPool(5, 20);
201 201 Assert.AreEqual(5, pool.PoolSize);
202 202 pool.Dispose();
203 203 Thread.Sleep(500);
204 204 Assert.AreEqual(0, pool.PoolSize);
205 205 pool.Dispose();
206 206 }
207 207
208 208 [TestMethod]
209 209 public void MTQueueTest() {
210 210 var queue = new MTQueue<int>();
211 211 int res;
212 212
213 213 queue.Enqueue(10);
214 214 Assert.IsTrue(queue.TryDequeue(out res));
215 215 Assert.AreEqual(10, res);
216 216 Assert.IsFalse(queue.TryDequeue(out res));
217 217
218 218 for (int i = 0; i < 1000; i++)
219 219 queue.Enqueue(i);
220 220
221 221 for (int i = 0; i < 1000; i++) {
222 222 queue.TryDequeue(out res);
223 223 Assert.AreEqual(i, res);
224 224 }
225 225
226 226 int writers = 0;
227 227 int readers = 0;
228 228 var stop = new ManualResetEvent(false);
229 229 int total = 0;
230 230
231 231 const int itemsPerWriter = 10000;
232 232 const int writersCount = 10;
233 233
234 234 for (int i = 0; i < writersCount; i++) {
235 235 Interlocked.Increment(ref writers);
236 236 AsyncPool
237 237 .InvokeNewThread(() => {
238 238 for (int ii = 0; ii < itemsPerWriter; ii++) {
239 239 queue.Enqueue(1);
240 240 }
241 241 return 1;
242 242 })
243 243 .Anyway(() => Interlocked.Decrement(ref writers));
244 244 }
245 245
246 246 for (int i = 0; i < 10; i++) {
247 247 Interlocked.Increment(ref readers);
248 248 AsyncPool
249 249 .InvokeNewThread(() => {
250 250 int t;
251 251 do {
252 252 while (queue.TryDequeue(out t))
253 253 Interlocked.Add(ref total, t);
254 254 } while (writers > 0);
255 255 return 1;
256 256 })
257 257 .Anyway(() => {
258 258 Interlocked.Decrement(ref readers);
259 259 if (readers == 0)
260 260 stop.Set();
261 261 });
262 262 }
263 263
264 264 stop.WaitOne();
265 265
266 266 Assert.AreEqual(itemsPerWriter * writersCount, total);
267 267 }
268 268
269 269 [TestMethod]
270 270 public void ParallelMapTest() {
271 271
272 272 const int count = 100000;
273 273
274 274 var args = new double[count];
275 275 var rand = new Random();
276 276
277 277 for (int i = 0; i < count; i++)
278 278 args[i] = rand.NextDouble();
279 279
280 280 var t = Environment.TickCount;
281 281 var res = args.ParallelMap(x => Math.Sin(x*x), 4).Join();
282 282
283 283 Console.WriteLine("Map complete in {0} ms", Environment.TickCount - t);
284 284
285 285 t = Environment.TickCount;
286 286 for (int i = 0; i < count; i++)
287 287 Assert.AreEqual(Math.Sin(args[i] * args[i]), res[i]);
288 288 Console.WriteLine("Verified in {0} ms", Environment.TickCount - t);
289 289 }
290 290
291 291 [TestMethod]
292 292 public void ChainedMapTest() {
293 293
294 using (var pool = new WorkerPool(0,100,100)) {
294 using (var pool = new WorkerPool(0,10,100)) {
295 295 const int count = 10000;
296 296
297 297 var args = new double[count];
298 298 var rand = new Random();
299 299
300 300 for (int i = 0; i < count; i++)
301 301 args[i] = rand.NextDouble();
302 302
303 303 var t = Environment.TickCount;
304 304 var res = args
305 305 .ChainedMap(
306 306 // Analysis disable once AccessToDisposedClosure
307 307 x => pool.Invoke(
308 308 () => Math.Sin(x * x)
309 309 ),
310 310 4
311 311 )
312 312 .Join();
313 313
314 314 Console.WriteLine("Map complete in {0} ms", Environment.TickCount - t);
315 315
316 316 t = Environment.TickCount;
317 317 for (int i = 0; i < count; i++)
318 318 Assert.AreEqual(Math.Sin(args[i] * args[i]), res[i]);
319 319 Console.WriteLine("Verified in {0} ms", Environment.TickCount - t);
320 320 Console.WriteLine("Max workers: {0}", pool.MaxRunningThreads);
321 321 }
322 322 }
323 323
324 324 [TestMethod]
325 325 public void ParallelForEachTest() {
326 326
327 327 const int count = 100000;
328 328
329 329 var args = new int[count];
330 330 var rand = new Random();
331 331
332 332 for (int i = 0; i < count; i++)
333 333 args[i] = (int)(rand.NextDouble() * 100);
334 334
335 335 int result = 0;
336 336
337 337 var t = Environment.TickCount;
338 338 args.ParallelForEach(x => Interlocked.Add(ref result, x), 4).Join();
339 339
340 340 Console.WriteLine("Iteration complete in {0} ms, result: {1}", Environment.TickCount - t, result);
341 341
342 342 int result2 = 0;
343 343
344 344 t = Environment.TickCount;
345 345 for (int i = 0; i < count; i++)
346 346 result2 += args[i];
347 347 Assert.AreEqual(result2, result);
348 348 Console.WriteLine("Verified in {0} ms", Environment.TickCount - t);
349 349 }
350 350
351 351 [TestMethod]
352 352 public void ComplexCase1Test() {
353 353 var flags = new bool[3];
354 354
355 355 // op1 (aync 200ms) => op2 (async 200ms) => op3 (sync map)
356 356
357 357 var step1 = PromiseHelper
358 358 .Sleep(200, "Alan")
359 359 .Cancelled(() => flags[0] = true);
360 360 var p = step1
361 361 .Chain(x =>
362 362 PromiseHelper
363 363 .Sleep(200, "Hi, " + x)
364 364 .Then(y => y)
365 365 .Cancelled(() => flags[1] = true)
366 366 )
367 367 .Cancelled(() => flags[2] = true);
368 368 step1.Join();
369 369 p.Cancel();
370 370 try {
371 371 Assert.AreEqual(p.Join(), "Hi, Alan");
372 372 Assert.Fail("Shouldn't get here");
373 373 } catch (OperationCanceledException) {
374 374 }
375 375
376 376 Assert.IsFalse(flags[0]);
377 377 Assert.IsTrue(flags[1]);
378 378 Assert.IsTrue(flags[2]);
379 379 }
380 380
381 381 [TestMethod]
382 382 public void ChainedCancel1Test() {
383 383 // ΠΏΡ€ΠΈ ΠΎΡ‚ΠΌΠ΅Π½Π΅ сцСплСнной асинхронной ΠΎΠΏΠ΅Ρ€Π°Ρ†ΠΈΠΈ всС ΠΎΠ±Π΅Ρ‰Π°Π½ΠΈΠ΅ Π΄ΠΎΠ»ΠΆΠ½ΠΎ
384 384 // Π·Π°Π²Π΅Ρ€ΡˆΠ°Ρ‚ΡŒΡΡ ошибкой OperationCanceledException
385 385 var p = PromiseHelper
386 386 .Sleep(1, "Hi, HAL!")
387 387 .Then(x => {
388 388 // запускаСм Π΄Π²Π΅ асинхронныС ΠΎΠΏΠ΅Ρ€Π°Ρ†ΠΈΠΈ
389 389 var result = PromiseHelper.Sleep(1000, "HEM ENABLED!!!");
390 390 // вторая опСрация отмСняСт ΠΏΠ΅Ρ€Π²ΡƒΡŽ Π΄ΠΎ Π·Π°Π²Π΅Ρ€ΡˆΠ΅Π½ΠΈΡ
391 391 PromiseHelper
392 392 .Sleep(100, "HAL, STOP!")
393 393 .Then(result.Cancel);
394 394 return result;
395 395 });
396 396 try {
397 397 p.Join();
398 398 } catch (TargetInvocationException err) {
399 399 Assert.IsTrue(err.InnerException is OperationCanceledException);
400 400 }
401 401 }
402 402
403 403 [TestMethod]
404 404 public void ChainedCancel2Test() {
405 405 // ΠΏΡ€ΠΈ ΠΎΡ‚ΠΌΠ΅Π½Π΅ Ρ†Π΅ΠΏΠΎΡ‡ΠΊΠΈ ΠΎΠ±Π΅Ρ‰Π°Π½ΠΈΠΉ, Π²Π»ΠΎΠΆΠ΅Π½Π½Ρ‹Π΅ ΠΎΠΏΠ΅Ρ€Π°Ρ†ΠΈΠΈ Ρ‚Π°ΠΊΠΆΠ΅ Π΄ΠΎΠ»ΠΆΠ½Ρ‹ ΠΎΡ‚ΠΌΠ΅Π½ΡΡ‚ΡŒΡΡ
406 406 var pSurvive = new Promise<bool>();
407 407 var hemStarted = new ManualResetEvent(false);
408 408 var p = PromiseHelper
409 409 .Sleep(1, "Hi, HAL!")
410 410 .Chain(x => {
411 411 hemStarted.Set();
412 412 // запускаСм Π΄Π²Π΅ асинхронныС ΠΎΠΏΠ΅Ρ€Π°Ρ†ΠΈΠΈ
413 413 var result = PromiseHelper
414 414 .Sleep(10000, "HEM ENABLED!!!")
415 415 .Then(s => pSurvive.Resolve(false));
416 416
417 417 result
418 418 .Cancelled(() => pSurvive.Resolve(true));
419 419
420 420 return result;
421 421 });
422 422
423 423 hemStarted.WaitOne();
424 424 p.Cancel();
425 425
426 426 try {
427 427 p.Join();
428 428 } catch (OperationCanceledException) {
429 429 Assert.IsTrue(pSurvive.Join());
430 430 }
431 431 }
432 432 }
433 433 }
434 434
@@ -1,290 +1,287
1 1 ο»Ώ
2 2 Microsoft Visual Studio Solution File, Format Version 11.00
3 3 # Visual Studio 2010
4 4 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Implab", "Implab\Implab.csproj", "{F550F1F8-8746-4AD0-9614-855F4C4B7F05}"
5 5 EndProject
6 6 Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{CE8D8D18-437A-445C-B662-4C2CE79A76F6}"
7 7 ProjectSection(SolutionItems) = preProject
8 8 Implab.vsmdi = Implab.vsmdi
9 9 Local.testsettings = Local.testsettings
10 10 TraceAndTestImpact.testsettings = TraceAndTestImpact.testsettings
11 11 EndProjectSection
12 12 EndProject
13 13 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Implab.Fx", "Implab.Fx\Implab.Fx.csproj", "{06E706F8-6881-43EB-927E-FFC503AF6ABC}"
14 14 EndProject
15 15 Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Tests", "Tests", "{BCA337C3-BFDC-4825-BBDB-E6D467E4E452}"
16 16 EndProject
17 17 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Implab.Test.mono", "Implab.Test\Implab.Test.mono.csproj", "{2BD05F84-E067-4B87-9477-FDC2676A21C6}"
18 18 EndProject
19 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Implab.Fx.Test.mono", "Implab.Fx.Test\Implab.Fx.Test.mono.csproj", "{2BD05F84-E067-4B87-9477-FDC2676A21C6}"
20 EndProject
21 19 Global
22 20 GlobalSection(SolutionConfigurationPlatforms) = preSolution
23 21 Debug|Any CPU = Debug|Any CPU
24 22 Release|Any CPU = Release|Any CPU
25 23 Debug 4.5|Any CPU = Debug 4.5|Any CPU
26 24 Release 4.5|Any CPU = Release 4.5|Any CPU
27 25 EndGlobalSection
28 26 GlobalSection(ProjectConfigurationPlatforms) = postSolution
29 27 {06E706F8-6881-43EB-927E-FFC503AF6ABC}.Debug 4.5|Any CPU.ActiveCfg = Debug 4.5|Any CPU
30 28 {06E706F8-6881-43EB-927E-FFC503AF6ABC}.Debug 4.5|Any CPU.Build.0 = Debug 4.5|Any CPU
31 29 {06E706F8-6881-43EB-927E-FFC503AF6ABC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
32 30 {06E706F8-6881-43EB-927E-FFC503AF6ABC}.Debug|Any CPU.Build.0 = Debug|Any CPU
33 31 {06E706F8-6881-43EB-927E-FFC503AF6ABC}.Release 4.5|Any CPU.ActiveCfg = Release 4.5|Any CPU
34 32 {06E706F8-6881-43EB-927E-FFC503AF6ABC}.Release 4.5|Any CPU.Build.0 = Release 4.5|Any CPU
35 33 {06E706F8-6881-43EB-927E-FFC503AF6ABC}.Release|Any CPU.ActiveCfg = Release|Any CPU
36 34 {06E706F8-6881-43EB-927E-FFC503AF6ABC}.Release|Any CPU.Build.0 = Release|Any CPU
37 35 {2BD05F84-E067-4B87-9477-FDC2676A21C6}.Debug 4.5|Any CPU.ActiveCfg = Debug 4.5|Any CPU
38 36 {2BD05F84-E067-4B87-9477-FDC2676A21C6}.Debug 4.5|Any CPU.ActiveCfg = Debug 4.5|Any CPU
39 37 {2BD05F84-E067-4B87-9477-FDC2676A21C6}.Debug 4.5|Any CPU.Build.0 = Debug 4.5|Any CPU
40 38 {2BD05F84-E067-4B87-9477-FDC2676A21C6}.Debug 4.5|Any CPU.Build.0 = Debug 4.5|Any CPU
41 39 {2BD05F84-E067-4B87-9477-FDC2676A21C6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
42 40 {2BD05F84-E067-4B87-9477-FDC2676A21C6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
43 41 {2BD05F84-E067-4B87-9477-FDC2676A21C6}.Debug|Any CPU.Build.0 = Debug|Any CPU
44 42 {2BD05F84-E067-4B87-9477-FDC2676A21C6}.Debug|Any CPU.Build.0 = Debug|Any CPU
45 43 {2BD05F84-E067-4B87-9477-FDC2676A21C6}.Release 4.5|Any CPU.ActiveCfg = Release 4.5|Any CPU
46 44 {2BD05F84-E067-4B87-9477-FDC2676A21C6}.Release 4.5|Any CPU.ActiveCfg = Release 4.5|Any CPU
47 45 {2BD05F84-E067-4B87-9477-FDC2676A21C6}.Release 4.5|Any CPU.Build.0 = Release 4.5|Any CPU
48 46 {2BD05F84-E067-4B87-9477-FDC2676A21C6}.Release 4.5|Any CPU.Build.0 = Release 4.5|Any CPU
49 47 {2BD05F84-E067-4B87-9477-FDC2676A21C6}.Release|Any CPU.ActiveCfg = Release|Any CPU
50 48 {2BD05F84-E067-4B87-9477-FDC2676A21C6}.Release|Any CPU.ActiveCfg = Release|Any CPU
51 49 {2BD05F84-E067-4B87-9477-FDC2676A21C6}.Release|Any CPU.Build.0 = Release|Any CPU
52 50 {2BD05F84-E067-4B87-9477-FDC2676A21C6}.Release|Any CPU.Build.0 = Release|Any CPU
53 51 {2F31E405-E267-4195-A05D-574093C21209}.Debug 4.5|Any CPU.ActiveCfg = Debug 4.5|Any CPU
54 52 {2F31E405-E267-4195-A05D-574093C21209}.Debug 4.5|Any CPU.Build.0 = Debug 4.5|Any CPU
55 53 {2F31E405-E267-4195-A05D-574093C21209}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
56 54 {2F31E405-E267-4195-A05D-574093C21209}.Debug|Any CPU.Build.0 = Debug|Any CPU
57 55 {2F31E405-E267-4195-A05D-574093C21209}.Release 4.5|Any CPU.ActiveCfg = Release 4.5|Any CPU
58 56 {2F31E405-E267-4195-A05D-574093C21209}.Release 4.5|Any CPU.Build.0 = Release 4.5|Any CPU
59 57 {2F31E405-E267-4195-A05D-574093C21209}.Release|Any CPU.ActiveCfg = Release|Any CPU
60 58 {2F31E405-E267-4195-A05D-574093C21209}.Release|Any CPU.Build.0 = Release|Any CPU
61 59 {63F92C0C-61BF-48C0-A377-8D67C3C661D0}.Debug 4.5|Any CPU.ActiveCfg = Debug 4.5|Any CPU
62 60 {63F92C0C-61BF-48C0-A377-8D67C3C661D0}.Debug 4.5|Any CPU.Build.0 = Debug 4.5|Any CPU
63 61 {63F92C0C-61BF-48C0-A377-8D67C3C661D0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
64 62 {63F92C0C-61BF-48C0-A377-8D67C3C661D0}.Debug|Any CPU.Build.0 = Debug|Any CPU
65 63 {63F92C0C-61BF-48C0-A377-8D67C3C661D0}.Release 4.5|Any CPU.ActiveCfg = Release 4.5|Any CPU
66 64 {63F92C0C-61BF-48C0-A377-8D67C3C661D0}.Release 4.5|Any CPU.Build.0 = Release 4.5|Any CPU
67 65 {63F92C0C-61BF-48C0-A377-8D67C3C661D0}.Release|Any CPU.ActiveCfg = Release|Any CPU
68 66 {63F92C0C-61BF-48C0-A377-8D67C3C661D0}.Release|Any CPU.Build.0 = Release|Any CPU
69 67 {F550F1F8-8746-4AD0-9614-855F4C4B7F05}.Debug 4.5|Any CPU.ActiveCfg = Debug 4.5|Any CPU
70 68 {F550F1F8-8746-4AD0-9614-855F4C4B7F05}.Debug 4.5|Any CPU.Build.0 = Debug 4.5|Any CPU
71 69 {F550F1F8-8746-4AD0-9614-855F4C4B7F05}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
72 70 {F550F1F8-8746-4AD0-9614-855F4C4B7F05}.Debug|Any CPU.Build.0 = Debug|Any CPU
73 71 {F550F1F8-8746-4AD0-9614-855F4C4B7F05}.Release 4.5|Any CPU.ActiveCfg = Release 4.5|Any CPU
74 72 {F550F1F8-8746-4AD0-9614-855F4C4B7F05}.Release 4.5|Any CPU.Build.0 = Release 4.5|Any CPU
75 73 {F550F1F8-8746-4AD0-9614-855F4C4B7F05}.Release|Any CPU.ActiveCfg = Release|Any CPU
76 74 {F550F1F8-8746-4AD0-9614-855F4C4B7F05}.Release|Any CPU.Build.0 = Release|Any CPU
77 75 EndGlobalSection
78 76 GlobalSection(NestedProjects) = preSolution
79 77 {2BD05F84-E067-4B87-9477-FDC2676A21C6} = {BCA337C3-BFDC-4825-BBDB-E6D467E4E452}
80 {2BD05F84-E067-4B87-9477-FDC2676A21C6} = {BCA337C3-BFDC-4825-BBDB-E6D467E4E452}
81 78 EndGlobalSection
82 79 GlobalSection(MonoDevelopProperties) = preSolution
83 80 StartupItem = Implab\Implab.csproj
84 81 Policies = $0
85 82 $0.CSharpFormattingPolicy = $1
86 83 $1.IndentSwitchBody = True
87 84 $1.NamespaceBraceStyle = EndOfLine
88 85 $1.ClassBraceStyle = EndOfLine
89 86 $1.InterfaceBraceStyle = EndOfLine
90 87 $1.StructBraceStyle = EndOfLine
91 88 $1.EnumBraceStyle = EndOfLine
92 89 $1.MethodBraceStyle = EndOfLine
93 90 $1.ConstructorBraceStyle = EndOfLine
94 91 $1.DestructorBraceStyle = EndOfLine
95 92 $1.BeforeMethodDeclarationParentheses = False
96 93 $1.BeforeMethodCallParentheses = False
97 94 $1.BeforeConstructorDeclarationParentheses = False
98 95 $1.NewLineBeforeConstructorInitializerColon = NewLine
99 96 $1.NewLineAfterConstructorInitializerColon = SameLine
100 97 $1.BeforeIndexerDeclarationBracket = False
101 98 $1.BeforeDelegateDeclarationParentheses = False
102 99 $1.NewParentheses = False
103 100 $1.SpacesBeforeBrackets = False
104 101 $1.inheritsSet = Mono
105 102 $1.inheritsScope = text/x-csharp
106 103 $1.scope = text/x-csharp
107 104 $0.TextStylePolicy = $2
108 105 $2.FileWidth = 120
109 106 $2.EolMarker = Unix
110 107 $2.inheritsSet = VisualStudio
111 108 $2.inheritsScope = text/plain
112 109 $2.scope = text/x-csharp
113 110 $0.DotNetNamingPolicy = $3
114 111 $3.DirectoryNamespaceAssociation = PrefixedHierarchical
115 112 $3.ResourceNamePolicy = MSBuild
116 113 $0.TextStylePolicy = $4
117 114 $4.FileWidth = 120
118 115 $4.TabsToSpaces = False
119 116 $4.inheritsSet = VisualStudio
120 117 $4.inheritsScope = text/plain
121 118 $4.scope = application/xml
122 119 $0.XmlFormattingPolicy = $5
123 120 $5.inheritsSet = Mono
124 121 $5.inheritsScope = application/xml
125 122 $5.scope = application/xml
126 123 $0.TextStylePolicy = $6
127 124 $6.FileWidth = 120
128 125 $6.TabsToSpaces = False
129 126 $6.inheritsSet = VisualStudio
130 127 $6.inheritsScope = text/plain
131 128 $6.scope = text/plain
132 129 $0.NameConventionPolicy = $7
133 130 $7.Rules = $8
134 131 $8.NamingRule = $9
135 132 $9.Name = Namespaces
136 133 $9.AffectedEntity = Namespace
137 134 $9.VisibilityMask = VisibilityMask
138 135 $9.NamingStyle = PascalCase
139 136 $9.IncludeInstanceMembers = True
140 137 $9.IncludeStaticEntities = True
141 138 $8.NamingRule = $10
142 139 $10.Name = Types
143 140 $10.AffectedEntity = Class, Struct, Enum, Delegate
144 141 $10.VisibilityMask = VisibilityMask
145 142 $10.NamingStyle = PascalCase
146 143 $10.IncludeInstanceMembers = True
147 144 $10.IncludeStaticEntities = True
148 145 $8.NamingRule = $11
149 146 $11.Name = Interfaces
150 147 $11.RequiredPrefixes = $12
151 148 $12.String = I
152 149 $11.AffectedEntity = Interface
153 150 $11.VisibilityMask = VisibilityMask
154 151 $11.NamingStyle = PascalCase
155 152 $11.IncludeInstanceMembers = True
156 153 $11.IncludeStaticEntities = True
157 154 $8.NamingRule = $13
158 155 $13.Name = Attributes
159 156 $13.RequiredSuffixes = $14
160 157 $14.String = Attribute
161 158 $13.AffectedEntity = CustomAttributes
162 159 $13.VisibilityMask = VisibilityMask
163 160 $13.NamingStyle = PascalCase
164 161 $13.IncludeInstanceMembers = True
165 162 $13.IncludeStaticEntities = True
166 163 $8.NamingRule = $15
167 164 $15.Name = Event Arguments
168 165 $15.RequiredSuffixes = $16
169 166 $16.String = EventArgs
170 167 $15.AffectedEntity = CustomEventArgs
171 168 $15.VisibilityMask = VisibilityMask
172 169 $15.NamingStyle = PascalCase
173 170 $15.IncludeInstanceMembers = True
174 171 $15.IncludeStaticEntities = True
175 172 $8.NamingRule = $17
176 173 $17.Name = Exceptions
177 174 $17.RequiredSuffixes = $18
178 175 $18.String = Exception
179 176 $17.AffectedEntity = CustomExceptions
180 177 $17.VisibilityMask = VisibilityMask
181 178 $17.NamingStyle = PascalCase
182 179 $17.IncludeInstanceMembers = True
183 180 $17.IncludeStaticEntities = True
184 181 $8.NamingRule = $19
185 182 $19.Name = Methods
186 183 $19.AffectedEntity = Methods
187 184 $19.VisibilityMask = VisibilityMask
188 185 $19.NamingStyle = PascalCase
189 186 $19.IncludeInstanceMembers = True
190 187 $19.IncludeStaticEntities = True
191 188 $8.NamingRule = $20
192 189 $20.Name = Static Readonly Fields
193 190 $20.AffectedEntity = ReadonlyField
194 191 $20.VisibilityMask = Internal, Protected, Public
195 192 $20.NamingStyle = PascalCase
196 193 $20.IncludeInstanceMembers = False
197 194 $20.IncludeStaticEntities = True
198 195 $8.NamingRule = $21
199 196 $21.Name = Fields (Non Private)
200 197 $21.AffectedEntity = Field
201 198 $21.VisibilityMask = Internal, Public
202 199 $21.NamingStyle = CamelCase
203 200 $21.IncludeInstanceMembers = True
204 201 $21.IncludeStaticEntities = True
205 202 $8.NamingRule = $22
206 203 $22.Name = ReadOnly Fields (Non Private)
207 204 $22.AffectedEntity = ReadonlyField
208 205 $22.VisibilityMask = Internal, Public
209 206 $22.NamingStyle = CamelCase
210 207 $22.IncludeInstanceMembers = True
211 208 $22.IncludeStaticEntities = False
212 209 $8.NamingRule = $23
213 210 $23.Name = Fields (Private)
214 211 $23.RequiredPrefixes = $24
215 212 $24.String = m_
216 213 $23.AffectedEntity = Field, ReadonlyField
217 214 $23.VisibilityMask = Private, Protected
218 215 $23.NamingStyle = CamelCase
219 216 $23.IncludeInstanceMembers = True
220 217 $23.IncludeStaticEntities = False
221 218 $8.NamingRule = $25
222 219 $25.Name = Static Fields (Private)
223 220 $25.RequiredPrefixes = $26
224 221 $26.String = _
225 222 $25.AffectedEntity = Field
226 223 $25.VisibilityMask = Private
227 224 $25.NamingStyle = CamelCase
228 225 $25.IncludeInstanceMembers = False
229 226 $25.IncludeStaticEntities = True
230 227 $8.NamingRule = $27
231 228 $27.Name = ReadOnly Fields (Private)
232 229 $27.RequiredPrefixes = $28
233 230 $28.String = m_
234 231 $27.AffectedEntity = ReadonlyField
235 232 $27.VisibilityMask = Private, Protected
236 233 $27.NamingStyle = CamelCase
237 234 $27.IncludeInstanceMembers = True
238 235 $27.IncludeStaticEntities = False
239 236 $8.NamingRule = $29
240 237 $29.Name = Constant Fields
241 238 $29.AffectedEntity = ConstantField
242 239 $29.VisibilityMask = VisibilityMask
243 240 $29.NamingStyle = AllUpper
244 241 $29.IncludeInstanceMembers = True
245 242 $29.IncludeStaticEntities = True
246 243 $8.NamingRule = $30
247 244 $30.Name = Properties
248 245 $30.AffectedEntity = Property
249 246 $30.VisibilityMask = VisibilityMask
250 247 $30.NamingStyle = PascalCase
251 248 $30.IncludeInstanceMembers = True
252 249 $30.IncludeStaticEntities = True
253 250 $8.NamingRule = $31
254 251 $31.Name = Events
255 252 $31.AffectedEntity = Event
256 253 $31.VisibilityMask = VisibilityMask
257 254 $31.NamingStyle = PascalCase
258 255 $31.IncludeInstanceMembers = True
259 256 $31.IncludeStaticEntities = True
260 257 $8.NamingRule = $32
261 258 $32.Name = Enum Members
262 259 $32.AffectedEntity = EnumMember
263 260 $32.VisibilityMask = VisibilityMask
264 261 $32.NamingStyle = PascalCase
265 262 $32.IncludeInstanceMembers = True
266 263 $32.IncludeStaticEntities = True
267 264 $8.NamingRule = $33
268 265 $33.Name = Parameters
269 266 $33.AffectedEntity = Parameter, LocalVariable
270 267 $33.VisibilityMask = VisibilityMask
271 268 $33.NamingStyle = CamelCase
272 269 $33.IncludeInstanceMembers = True
273 270 $33.IncludeStaticEntities = True
274 271 $8.NamingRule = $34
275 272 $34.Name = Type Parameters
276 273 $34.RequiredPrefixes = $35
277 274 $35.String = T
278 275 $34.AffectedEntity = TypeParameter
279 276 $34.VisibilityMask = VisibilityMask
280 277 $34.NamingStyle = PascalCase
281 278 $34.IncludeInstanceMembers = True
282 279 $34.IncludeStaticEntities = True
283 280 EndGlobalSection
284 281 GlobalSection(TestCaseManagementSettings) = postSolution
285 282 CategoryFile = Implab.vsmdi
286 283 EndGlobalSection
287 284 GlobalSection(SolutionProperties) = preSolution
288 285 HideSolutionNode = FALSE
289 286 EndGlobalSection
290 287 EndGlobal
@@ -1,196 +1,200
1 1 ο»Ώ<?xml version="1.0" encoding="utf-8"?>
2 2 <Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
3 3 <PropertyGroup>
4 4 <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
5 5 <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
6 6 <ProjectGuid>{F550F1F8-8746-4AD0-9614-855F4C4B7F05}</ProjectGuid>
7 7 <OutputType>Library</OutputType>
8 8 <RootNamespace>Implab</RootNamespace>
9 9 <AssemblyName>Implab</AssemblyName>
10 <ProductVersion>8.0.30703</ProductVersion>
11 <SchemaVersion>2.0</SchemaVersion>
10 12 </PropertyGroup>
11 13 <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
12 14 <DebugSymbols>true</DebugSymbols>
13 15 <DebugType>full</DebugType>
14 16 <Optimize>false</Optimize>
15 17 <OutputPath>bin\Debug</OutputPath>
16 18 <DefineConstants>TRACE;DEBUG;</DefineConstants>
17 19 <ErrorReport>prompt</ErrorReport>
18 20 <WarningLevel>4</WarningLevel>
19 21 <ConsolePause>false</ConsolePause>
20 22 <RunCodeAnalysis>true</RunCodeAnalysis>
21 23 </PropertyGroup>
22 24 <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
23 25 <DebugType>full</DebugType>
24 26 <Optimize>true</Optimize>
25 27 <OutputPath>bin\Release</OutputPath>
26 28 <ErrorReport>prompt</ErrorReport>
27 29 <WarningLevel>4</WarningLevel>
28 30 <ConsolePause>false</ConsolePause>
29 31 </PropertyGroup>
30 32 <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug 4.5|AnyCPU' ">
31 33 <DebugSymbols>true</DebugSymbols>
32 34 <DebugType>full</DebugType>
33 35 <Optimize>false</Optimize>
34 36 <OutputPath>bin\Debug</OutputPath>
35 37 <DefineConstants>TRACE;DEBUG;NET_4_5</DefineConstants>
36 38 <ErrorReport>prompt</ErrorReport>
37 39 <WarningLevel>4</WarningLevel>
38 40 <RunCodeAnalysis>true</RunCodeAnalysis>
39 41 <ConsolePause>false</ConsolePause>
40 42 </PropertyGroup>
41 43 <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release 4.5|AnyCPU' ">
42 44 <Optimize>true</Optimize>
43 45 <OutputPath>bin\Release</OutputPath>
44 46 <ErrorReport>prompt</ErrorReport>
45 47 <WarningLevel>4</WarningLevel>
46 48 <ConsolePause>false</ConsolePause>
47 49 <DefineConstants>NET_4_5</DefineConstants>
48 50 </PropertyGroup>
49 51 <ItemGroup>
50 52 <Reference Include="System" />
51 53 <Reference Include="System.Xml" />
52 54 </ItemGroup>
53 55 <ItemGroup>
54 56 <Compile Include="Component.cs" />
55 57 <Compile Include="CustomEqualityComparer.cs" />
56 58 <Compile Include="Diagnostics\ConsoleTraceListener.cs" />
57 59 <Compile Include="Diagnostics\EventText.cs" />
58 60 <Compile Include="Diagnostics\IEventTextFormatter.cs" />
59 61 <Compile Include="Diagnostics\LogChannel.cs" />
60 62 <Compile Include="Diagnostics\LogicalOperation.cs" />
61 63 <Compile Include="Diagnostics\TextFileListener.cs" />
62 64 <Compile Include="Diagnostics\TextListenerBase.cs" />
63 65 <Compile Include="Diagnostics\TraceLog.cs" />
64 66 <Compile Include="Diagnostics\TraceContext.cs" />
65 67 <Compile Include="Diagnostics\TraceEvent.cs" />
66 68 <Compile Include="Diagnostics\TraceEventType.cs" />
67 69 <Compile Include="Disposable.cs" />
68 70 <Compile Include="ICancellable.cs" />
69 71 <Compile Include="IProgressHandler.cs" />
70 72 <Compile Include="IProgressNotifier.cs" />
71 73 <Compile Include="IPromiseT.cs" />
72 74 <Compile Include="IPromise.cs" />
73 75 <Compile Include="IServiceLocator.cs" />
74 76 <Compile Include="ITaskController.cs" />
75 77 <Compile Include="JSON\JSONElementContext.cs" />
76 78 <Compile Include="JSON\JSONElementType.cs" />
77 79 <Compile Include="JSON\JSONGrammar.cs" />
78 80 <Compile Include="JSON\JSONParser.cs" />
79 81 <Compile Include="JSON\JSONScanner.cs" />
80 82 <Compile Include="JSON\JsonTokenType.cs" />
81 83 <Compile Include="JSON\JSONWriter.cs" />
82 84 <Compile Include="JSON\JSONXmlReader.cs" />
83 85 <Compile Include="JSON\JSONXmlReaderOptions.cs" />
84 86 <Compile Include="JSON\StringTranslator.cs" />
85 87 <Compile Include="Parallels\DispatchPool.cs" />
86 88 <Compile Include="Parallels\ArrayTraits.cs" />
87 89 <Compile Include="Parallels\MTQueue.cs" />
88 90 <Compile Include="Parallels\WorkerPool.cs" />
89 91 <Compile Include="Parsing\Alphabet.cs" />
90 92 <Compile Include="Parsing\AlphabetBase.cs" />
91 93 <Compile Include="Parsing\AltToken.cs" />
92 94 <Compile Include="Parsing\BinaryToken.cs" />
93 95 <Compile Include="Parsing\CatToken.cs" />
94 96 <Compile Include="Parsing\CDFADefinition.cs" />
95 97 <Compile Include="Parsing\DFABuilder.cs" />
96 98 <Compile Include="Parsing\DFADefinitionBase.cs" />
97 99 <Compile Include="Parsing\DFAStateDescriptor.cs" />
98 100 <Compile Include="Parsing\DFAutomaton.cs" />
99 101 <Compile Include="Parsing\EDFADefinition.cs" />
100 102 <Compile Include="Parsing\EmptyToken.cs" />
101 103 <Compile Include="Parsing\EndToken.cs" />
102 104 <Compile Include="Parsing\EnumAlphabet.cs" />
103 105 <Compile Include="Parsing\Grammar.cs" />
104 106 <Compile Include="Parsing\IAlphabet.cs" />
105 107 <Compile Include="Parsing\IDFADefinition.cs" />
106 108 <Compile Include="Parsing\IVisitor.cs" />
107 109 <Compile Include="Parsing\ParserException.cs" />
108 110 <Compile Include="Parsing\Scanner.cs" />
109 111 <Compile Include="Parsing\StarToken.cs" />
110 112 <Compile Include="Parsing\SymbolToken.cs" />
111 113 <Compile Include="Parsing\Token.cs" />
112 114 <Compile Include="SafePool.cs" />
113 115 <Compile Include="ServiceLocator.cs" />
114 116 <Compile Include="TaskController.cs" />
115 117 <Compile Include="ProgressInitEventArgs.cs" />
116 118 <Compile Include="Properties\AssemblyInfo.cs" />
117 119 <Compile Include="Promise.cs" />
118 120 <Compile Include="Parallels\AsyncPool.cs" />
119 121 <Compile Include="Safe.cs" />
120 122 <Compile Include="ValueEventArgs.cs" />
121 123 <Compile Include="PromiseExtensions.cs" />
122 124 <Compile Include="TransientPromiseException.cs" />
123 125 <Compile Include="SyncContextPromise.cs" />
126 <Compile Include="SyncPool.cs" />
127 <Compile Include="SyncPoolWrapper.cs" />
124 128 </ItemGroup>
125 129 <Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
126 130 <ItemGroup />
127 131 <ProjectExtensions>
128 132 <MonoDevelop>
129 133 <Properties>
130 134 <Policies>
131 135 <CSharpFormattingPolicy IndentSwitchBody="True" NamespaceBraceStyle="EndOfLine" ClassBraceStyle="EndOfLine" InterfaceBraceStyle="EndOfLine" StructBraceStyle="EndOfLine" EnumBraceStyle="EndOfLine" MethodBraceStyle="EndOfLine" ConstructorBraceStyle="EndOfLine" DestructorBraceStyle="EndOfLine" BeforeMethodDeclarationParentheses="False" BeforeMethodCallParentheses="False" BeforeConstructorDeclarationParentheses="False" NewLineBeforeConstructorInitializerColon="NewLine" NewLineAfterConstructorInitializerColon="SameLine" BeforeIndexerDeclarationBracket="False" BeforeDelegateDeclarationParentheses="False" NewParentheses="False" SpacesBeforeBrackets="False" inheritsSet="Mono" inheritsScope="text/x-csharp" scope="text/x-csharp" />
132 136 <TextStylePolicy FileWidth="120" EolMarker="Unix" inheritsSet="VisualStudio" inheritsScope="text/plain" scope="text/x-csharp" />
133 137 <DotNetNamingPolicy DirectoryNamespaceAssociation="PrefixedHierarchical" ResourceNamePolicy="MSBuild" />
134 138 <TextStylePolicy FileWidth="120" TabsToSpaces="False" inheritsSet="VisualStudio" inheritsScope="text/plain" scope="application/xml" />
135 139 <XmlFormattingPolicy inheritsSet="Mono" inheritsScope="application/xml" scope="application/xml" />
136 140 <TextStylePolicy FileWidth="120" TabsToSpaces="False" inheritsSet="VisualStudio" inheritsScope="text/plain" scope="text/plain" />
137 141 <NameConventionPolicy>
138 142 <Rules>
139 143 <NamingRule Name="Namespaces" AffectedEntity="Namespace" VisibilityMask="VisibilityMask" NamingStyle="PascalCase" IncludeInstanceMembers="True" IncludeStaticEntities="True" />
140 144 <NamingRule Name="Types" AffectedEntity="Class, Struct, Enum, Delegate" VisibilityMask="VisibilityMask" NamingStyle="PascalCase" IncludeInstanceMembers="True" IncludeStaticEntities="True" />
141 145 <NamingRule Name="Interfaces" AffectedEntity="Interface" VisibilityMask="VisibilityMask" NamingStyle="PascalCase" IncludeInstanceMembers="True" IncludeStaticEntities="True">
142 146 <RequiredPrefixes>
143 147 <String>I</String>
144 148 </RequiredPrefixes>
145 149 </NamingRule>
146 150 <NamingRule Name="Attributes" AffectedEntity="CustomAttributes" VisibilityMask="VisibilityMask" NamingStyle="PascalCase" IncludeInstanceMembers="True" IncludeStaticEntities="True">
147 151 <RequiredSuffixes>
148 152 <String>Attribute</String>
149 153 </RequiredSuffixes>
150 154 </NamingRule>
151 155 <NamingRule Name="Event Arguments" AffectedEntity="CustomEventArgs" VisibilityMask="VisibilityMask" NamingStyle="PascalCase" IncludeInstanceMembers="True" IncludeStaticEntities="True">
152 156 <RequiredSuffixes>
153 157 <String>EventArgs</String>
154 158 </RequiredSuffixes>
155 159 </NamingRule>
156 160 <NamingRule Name="Exceptions" AffectedEntity="CustomExceptions" VisibilityMask="VisibilityMask" NamingStyle="PascalCase" IncludeInstanceMembers="True" IncludeStaticEntities="True">
157 161 <RequiredSuffixes>
158 162 <String>Exception</String>
159 163 </RequiredSuffixes>
160 164 </NamingRule>
161 165 <NamingRule Name="Methods" AffectedEntity="Methods" VisibilityMask="VisibilityMask" NamingStyle="PascalCase" IncludeInstanceMembers="True" IncludeStaticEntities="True" />
162 166 <NamingRule Name="Static Readonly Fields" AffectedEntity="ReadonlyField" VisibilityMask="Internal, Protected, Public" NamingStyle="CamelCase" IncludeInstanceMembers="False" IncludeStaticEntities="True" />
163 167 <NamingRule Name="Fields (Non Private)" AffectedEntity="Field" VisibilityMask="Internal, Public" NamingStyle="CamelCase" IncludeInstanceMembers="True" IncludeStaticEntities="True" />
164 168 <NamingRule Name="ReadOnly Fields (Non Private)" AffectedEntity="ReadonlyField" VisibilityMask="Internal, Public" NamingStyle="CamelCase" IncludeInstanceMembers="True" IncludeStaticEntities="False" />
165 169 <NamingRule Name="Fields (Private)" AffectedEntity="Field, ReadonlyField" VisibilityMask="Private, Protected" NamingStyle="CamelCase" IncludeInstanceMembers="True" IncludeStaticEntities="False">
166 170 <RequiredPrefixes>
167 171 <String>m_</String>
168 172 </RequiredPrefixes>
169 173 </NamingRule>
170 174 <NamingRule Name="Static Fields (Private)" AffectedEntity="Field" VisibilityMask="Private" NamingStyle="CamelCase" IncludeInstanceMembers="False" IncludeStaticEntities="True">
171 175 <RequiredPrefixes>
172 176 <String>_</String>
173 177 </RequiredPrefixes>
174 178 </NamingRule>
175 179 <NamingRule Name="ReadOnly Fields (Private)" AffectedEntity="ReadonlyField" VisibilityMask="Private, Protected" NamingStyle="CamelCase" IncludeInstanceMembers="True" IncludeStaticEntities="False">
176 180 <RequiredPrefixes>
177 181 <String>m_</String>
178 182 </RequiredPrefixes>
179 183 </NamingRule>
180 184 <NamingRule Name="Constant Fields" AffectedEntity="ConstantField" VisibilityMask="VisibilityMask" NamingStyle="AllUpper" IncludeInstanceMembers="True" IncludeStaticEntities="True" />
181 185 <NamingRule Name="Properties" AffectedEntity="Property" VisibilityMask="VisibilityMask" NamingStyle="PascalCase" IncludeInstanceMembers="True" IncludeStaticEntities="True" />
182 186 <NamingRule Name="Events" AffectedEntity="Event" VisibilityMask="VisibilityMask" NamingStyle="PascalCase" IncludeInstanceMembers="True" IncludeStaticEntities="True" />
183 187 <NamingRule Name="Enum Members" AffectedEntity="EnumMember" VisibilityMask="VisibilityMask" NamingStyle="PascalCase" IncludeInstanceMembers="True" IncludeStaticEntities="True" />
184 188 <NamingRule Name="Parameters" AffectedEntity="Parameter, LocalVariable" VisibilityMask="VisibilityMask" NamingStyle="CamelCase" IncludeInstanceMembers="True" IncludeStaticEntities="True" />
185 189 <NamingRule Name="Type Parameters" AffectedEntity="TypeParameter" VisibilityMask="VisibilityMask" NamingStyle="PascalCase" IncludeInstanceMembers="True" IncludeStaticEntities="True">
186 190 <RequiredPrefixes>
187 191 <String>T</String>
188 192 </RequiredPrefixes>
189 193 </NamingRule>
190 194 </Rules>
191 195 </NameConventionPolicy>
192 196 </Policies>
193 197 </Properties>
194 198 </MonoDevelop>
195 199 </ProjectExtensions>
196 200 </Project> No newline at end of file
@@ -1,62 +1,65
1 1 using System;
2 2 using System.Collections.Generic;
3 3 using System.Linq;
4 4 using System.Text;
5 5 using System.Xml;
6 6
7 7 namespace Implab.JSON {
8 8 /// <summary>
9 9 /// Набор Π½Π΅ΠΎΠ±ΡΠ·Π°Ρ‚Π΅Π»ΡŒΠ½Ρ‹Ρ… ΠΏΠ°Ρ€Π°ΠΌΠ΅Ρ‚Ρ€ΠΎΠ² для <see cref="JSONXmlReader"/>, ΠΏΠΎΠ·Π²ΠΎΠ»ΡΡŽΡ‰ΠΈΠΉ ΡƒΠΏΡ€Π°Π²Π»ΡΡ‚ΡŒ процСссом
10 10 /// ΠΈΠ½Ρ‚Π΅Ρ€ΠΏΡ€Π΅Ρ‚Π°Ρ†ΠΈΠΈ <c>JSON</c> Π΄ΠΎΠΊΡƒΠΌΠ΅Π½Ρ‚Π°.
11 11 /// </summary>
12 12 public class JSONXmlReaderOptions {
13 13 /// <summary>
14 14 /// ΠŸΡ€ΠΎΡΡ‚Ρ€Π°Π½ΡΡ‚Π²ΠΎ ΠΈΠΌΠ΅Π½ Π² ΠΊΠΎΡ‚ΠΎΡ€ΠΎΠΌ Π±ΡƒΠ΄ΡƒΡ‚ Ρ€Π°ΡΠΏΠΎΠ»Π°Π³Π°Ρ‚ΡŒΡΡ Ρ‡ΠΈΡ‚Π°Π΅ΠΌΡ‹Π΅ элСмСнты Π΄ΠΎΠΊΡƒΠΌΠ΅Π½Ρ‚Π°
15 15 /// </summary>
16 16 public string NamespaceURI {
17 17 get;
18 18 set;
19 19 }
20 20
21 21 /// <summary>
22 /// Π˜Π½Ρ‚Π΅Ρ€ΠΏΡ€Π΅Ρ‚ΠΈΡ€ΠΎΠ²Π°Ρ‚ΡŒ массивы ΠΊΠ°ΠΊ мноТСствСнныС элСмСнты (ΡƒΠ±ΠΈΡ€Π°Π΅Ρ‚ ΠΎΠ΄ΠΈΠ½ ΡƒΡ€ΠΎΠ²Π΅Π½ΡŒ влоТСнности)
22 /// Π˜Π½Ρ‚Π΅Ρ€ΠΏΡ€Π΅Ρ‚ΠΈΡ€ΠΎΠ²Π°Ρ‚ΡŒ массивы ΠΊΠ°ΠΊ мноТСствСнныС элСмСнты (ΡƒΠ±ΠΈΡ€Π°Π΅Ρ‚ ΠΎΠ΄ΠΈΠ½ ΡƒΡ€ΠΎΠ²Π΅Π½ΡŒ влоТСнности), ΠΈΠ½Π°Ρ‡Π΅ массив
23 /// прСдставляСтся Π² Π²ΠΈΠ΄Π΅ ΡƒΠ·Π»Π°, Π΄ΠΎΡ‡Π΅Ρ€Π½ΠΈΠΌΠΈ элСмСнтами ΠΊΠΎΡ‚ΠΎΡ€ΠΎΠ³ΠΎ ΡΠ²Π»ΡΡŽΡ‚ΡΡ элСмСнты массива, ΠΈΠΌΠ΅Π½Π° Π΄ΠΎΡ‡Π΅Ρ€Π½ΠΈΡ… элСмСнтов
24 /// ΠΎΠΏΡ€Π΅Π΄Π΅Π»ΡΡŽΡ‚ΡΡ свойством <see cref="ArrayItemName"/>. По ΡƒΠΌΠΎΠ»Ρ‡Π°Π½ΠΈΡŽ <c>false</c>.
23 25 /// </summary>
24 26 public bool FlattenArrays {
25 27 get;
26 28 set;
27 29 }
28 30
29 31 /// <summary>
30 32 /// ΠŸΡ€Π΅Ρ„ΠΈΠΊΡ, для ΡƒΠ·Π»ΠΎΠ² Π΄ΠΎΠΊΡƒΠΌΠ΅Π½Ρ‚Π°
31 33 /// </summary>
32 34 public string NodesPrefix {
33 35 get;
34 36 set;
35 37 }
36 38
37 39 /// <summary>
38 40 /// Имя ΠΊΠΎΡ€Π½Π΅Π²ΠΎΠ³ΠΎ элСмСнта Π² xml Π΄ΠΎΠΊΡƒΠΌΠ΅Π½Ρ‚Π΅
39 41 /// </summary>
40 42 public string RootName {
41 43 get;
42 44 set;
43 45 }
44 46
45 47 /// <summary>
46 48 /// Имя элСмСнта для массивов, Ссли Π½Π΅ Π²ΠΊΠ»ΡŽΡ‡Π΅Π½Π° опция <see cref="FlattenArrays"/>.
49 /// По ΡƒΠΌΠΎΠ»Ρ‡Π°Π½ΠΈΡŽ <c>item</c>.
47 50 /// </summary>
48 51 public string ArrayItemName {
49 52 get;
50 53 set;
51 54 }
52 55
53 56 /// <summary>
54 57 /// Π’Π°Π±Π»ΠΈΡ†Π° Π°Ρ‚ΠΎΠΌΠΈΠ·ΠΈΡ€ΠΎΠ²Π°Π½Π½Ρ‹Ρ… строк для построСния Π΄ΠΎΠΊΡƒΠΌΠ΅Π½Ρ‚Π°.
55 58 /// </summary>
56 59 public XmlNameTable NameTable {
57 60 get;
58 61 set;
59 62 }
60 63
61 64 }
62 65 }
@@ -1,193 +1,200
1 1 using Implab.Diagnostics;
2 2 using System;
3 3 using System.Collections.Generic;
4 4 using System.Diagnostics;
5 5 using System.Linq;
6 6 using System.Text;
7 7 using System.Threading;
8 8
9 9 namespace Implab.Parallels {
10 10 public static class ArrayTraits {
11 11 class ArrayIterator<TSrc> : DispatchPool<int> {
12 12 readonly Action<TSrc> m_action;
13 13 readonly TSrc[] m_source;
14 14 readonly Promise<int> m_promise = new Promise<int>();
15 15 readonly TraceContext m_traceContext;
16 16
17 17 int m_pending;
18 18 int m_next;
19 19
20 20 public ArrayIterator(TSrc[] source, Action<TSrc> action, int threads)
21 21 : base(threads) {
22 22
23 23 Debug.Assert(source != null);
24 24 Debug.Assert(action != null);
25 25
26 26 m_traceContext = TraceContext.Snapshot();
27 27 m_next = 0;
28 28 m_source = source;
29 29 m_pending = source.Length;
30 30 m_action = action;
31 31
32 32 m_promise.Anyway(Dispose);
33 33
34 34 InitPool();
35 35 }
36 36
37 37 public Promise<int> Promise {
38 38 get {
39 39 return m_promise;
40 40 }
41 41 }
42 42
43 43 protected override void Worker() {
44 44 TraceContext.Fork(m_traceContext);
45 45 base.Worker();
46 46 }
47 47
48 48 protected override bool TryDequeue(out int unit) {
49 49 unit = Interlocked.Increment(ref m_next) - 1;
50 50 return unit < m_source.Length;
51 51 }
52 52
53 53 protected override void InvokeUnit(int unit) {
54 54 try {
55 55 m_action(m_source[unit]);
56 56 var pending = Interlocked.Decrement(ref m_pending);
57 57 if (pending == 0)
58 58 m_promise.Resolve(m_source.Length);
59 59 } catch (Exception e) {
60 60 m_promise.Reject(e);
61 61 }
62 62 }
63 63 }
64 64
65 65 class ArrayMapper<TSrc, TDst>: DispatchPool<int> {
66 66 readonly Func<TSrc, TDst> m_transform;
67 67 readonly TSrc[] m_source;
68 68 readonly TDst[] m_dest;
69 69 readonly Promise<TDst[]> m_promise = new Promise<TDst[]>();
70 70 readonly TraceContext m_traceContext;
71 71
72 72 int m_pending;
73 73 int m_next;
74 74
75 75 public ArrayMapper(TSrc[] source, Func<TSrc, TDst> transform, int threads)
76 76 : base(threads) {
77 77
78 78 Debug.Assert (source != null);
79 79 Debug.Assert( transform != null);
80 80
81 81 m_next = 0;
82 82 m_source = source;
83 83 m_dest = new TDst[source.Length];
84 84 m_pending = source.Length;
85 85 m_transform = transform;
86 86 m_traceContext = TraceContext.Snapshot();
87 87
88 88 m_promise.Anyway(Dispose);
89 89
90 90 InitPool();
91 91 }
92 92
93 93 public Promise<TDst[]> Promise {
94 94 get {
95 95 return m_promise;
96 96 }
97 97 }
98 98
99 99 protected override void Worker() {
100 100 TraceContext.Fork(m_traceContext);
101 101 base.Worker();
102 102 }
103 103
104 104 protected override bool TryDequeue(out int unit) {
105 105 unit = Interlocked.Increment(ref m_next) - 1;
106 106 return unit >= m_source.Length ? false : true;
107 107 }
108 108
109 109 protected override void InvokeUnit(int unit) {
110 110 try {
111 111 m_dest[unit] = m_transform(m_source[unit]);
112 112 var pending = Interlocked.Decrement(ref m_pending);
113 113 if (pending == 0)
114 114 m_promise.Resolve(m_dest);
115 115 } catch (Exception e) {
116 116 m_promise.Reject(e);
117 117 }
118 118 }
119 119 }
120 120
121 121 public static IPromise<TDst[]> ParallelMap<TSrc, TDst> (this TSrc[] source, Func<TSrc,TDst> transform, int threads) {
122 122 if (source == null)
123 123 throw new ArgumentNullException("source");
124 124 if (transform == null)
125 125 throw new ArgumentNullException("transform");
126 126
127 127 var mapper = new ArrayMapper<TSrc, TDst>(source, transform, threads);
128 128 return mapper.Promise;
129 129 }
130 130
131 131 public static IPromise<int> ParallelForEach<TSrc>(this TSrc[] source, Action<TSrc> action, int threads) {
132 132 if (source == null)
133 133 throw new ArgumentNullException("source");
134 134 if (action == null)
135 135 throw new ArgumentNullException("action");
136 136
137 137 var iter = new ArrayIterator<TSrc>(source, action, threads);
138 138 return iter.Promise;
139 139 }
140 140
141 141 public static IPromise<TDst[]> ChainedMap<TSrc, TDst>(this TSrc[] source, ResultMapper<TSrc, IPromise<TDst>> transform, int threads) {
142 142 if (source == null)
143 143 throw new ArgumentNullException("source");
144 144 if (transform == null)
145 145 throw new ArgumentNullException("transform");
146 146 if (threads <= 0)
147 147 throw new ArgumentOutOfRangeException("Threads number must be greater then zero");
148 148
149 149 if (source.Length == 0)
150 150 return Promise<TDst[]>.ResultToPromise(new TDst[0]);
151 151
152 152 var promise = new Promise<TDst[]>();
153 153 var res = new TDst[source.Length];
154 154 var pending = source.Length;
155 155
156 var semaphore = new Semaphore(threads, threads);
156 object locker = new object();
157 int slots = threads;
157 158
158 159 // Analysis disable AccessToDisposedClosure
159 160 AsyncPool.InvokeNewThread(() => {
160 161 for (int i = 0; i < source.Length; i++) {
161 162 if(promise.IsResolved)
162 163 break; // stop processing in case of error or cancellation
163 164 var idx = i;
164 165
165 semaphore.WaitOne();
166 lock(locker) {
167 while(slots == 0)
168 Monitor.Wait(locker);
169 slots--;
170 }
166 171 try {
167 var p1 = transform(source[i]);
168 p1.Anyway(() => semaphore.Release());
169 p1.Then(
170 x => {
171 res[idx] = x;
172 var left = Interlocked.Decrement(ref pending);
173 if (left == 0)
174 promise.Resolve(res);
175 },
176 e => {
177 promise.Reject(e);
178 throw new TransientPromiseException(e);
179 }
180 );
172 transform(source[i])
173 .Anyway(() => {
174 lock(locker) {
175 slots ++;
176 Monitor.Pulse(locker);
177 }
178 })
179 .Last(
180 x => {
181 res[idx] = x;
182 var left = Interlocked.Decrement(ref pending);
183 if (left == 0)
184 promise.Resolve(res);
185 },
186 e => promise.Reject(e)
187 );
181 188
182 189 } catch (Exception e) {
183 190 promise.Reject(e);
184 191 }
185 192 }
186 193 return 0;
187 194 });
188 195
189 return promise.Anyway(semaphore.Dispose);
196 return promise;
190 197 }
191 198
192 199 }
193 200 }
@@ -1,334 +1,343
1 1 using System;
2 2 using System.Collections.Generic;
3 3 using System.Linq;
4 4 using System.Text;
5 5 using System.Threading;
6 6 using System.Diagnostics;
7 7
8 8 namespace Implab.Parallels {
9 9 public abstract class DispatchPool<TUnit> : IDisposable {
10 10 readonly int m_minThreads;
11 11 readonly int m_maxThreads;
12 readonly int m_releaseTimeout = 100; // the timeout while the working thread will wait for the new tasks before exit
12 13
13 14 int m_createdThreads = 0; // the current size of the pool
14 15 int m_activeThreads = 0; // the count of threads which are active
15 16 int m_sleepingThreads = 0; // the count of currently inactive threads
16 17 int m_maxRunningThreads = 0; // the meximum reached size of the pool
17 18 int m_exitRequired = 0; // the pool is going to shutdown, all unused workers are released
18 int m_releaseTimeout = 100; // the timeout while the working thread will wait for the new tasks before exit
19
19 20 int m_wakeEvents = 0; // the count of wake events
20 21
21 AutoResetEvent m_hasTasks = new AutoResetEvent(false);
22 readonly object m_signalLocker = new object();
22 23
23 24 protected DispatchPool(int min, int max) {
24 25 if (min < 0)
25 26 throw new ArgumentOutOfRangeException("min");
26 27 if (max <= 0)
27 28 throw new ArgumentOutOfRangeException("max");
28 29
29 30 if (min > max)
30 31 min = max;
31 32 m_minThreads = min;
32 33 m_maxThreads = max;
33 34 }
34 35
35 36 protected DispatchPool(int threads)
36 37 : this(threads, threads) {
37 38 }
38 39
39 40 protected DispatchPool() {
40 41 int maxThreads, maxCP;
41 42 ThreadPool.GetMaxThreads(out maxThreads, out maxCP);
42 43
43 44 m_minThreads = 0;
44 45 m_maxThreads = maxThreads;
45 46 }
46 47
47 48 protected void InitPool() {
48 49 for (int i = 0; i < m_minThreads; i++)
49 50 StartWorker();
50 51 }
51 52
52 53 public int PoolSize {
53 54 get {
55 Thread.MemoryBarrier();
54 56 return m_createdThreads;
55 57 }
56 58 }
57 59
58 60 public int ActiveThreads {
59 61 get {
62 Thread.MemoryBarrier();
60 63 return m_activeThreads;
61 64 }
62 65 }
63 66
64 67 public int MaxRunningThreads {
65 68 get {
69 Thread.MemoryBarrier();
66 70 return m_maxRunningThreads;
67 71 }
68 72 }
69 73
70 74 protected bool IsDisposed {
71 75 get {
72 return m_exitRequired != 0;
76 Thread.MemoryBarrier();
77 return m_exitRequired == 1;
73 78 }
74 79 }
75 80
76 81 protected abstract bool TryDequeue(out TUnit unit);
77 82
78 #region thread execution traits
83 #region thread signaling traits
79 84 int SignalThread() {
80 85 var signals = Interlocked.Increment(ref m_wakeEvents);
81 86 if(signals == 1)
82 m_hasTasks.Set();
87 lock(m_signalLocker)
88 Monitor.Pulse(m_signalLocker);
83 89 return signals;
84 90 }
85 91
86 92 bool FetchSignalOrWait(int timeout) {
87 93 var start = Environment.TickCount;
88
89 // ΠΎΠ·Π½Π°Ρ‡Π°Π΅Ρ‚, Ρ‡Ρ‚ΠΎ ΠΏΠΎΡ‚ΠΎΠΊ Π²Π»Π°Π΄Π΅Π΅Ρ‚ Π±Π»ΠΎΠΊΠΈΡ€ΠΎΠ²ΠΊΠΎΠΉ ΠΈ ΠΏΡ€ΠΈ ΡƒΡΠΏΠ΅ΡˆΠ½ΠΎΠΌ ΠΏΠΎΠ»ΡƒΡ‡Π΅Π½ΠΈΠΈ сигнала Π΄ΠΎΠ»ΠΆΠ΅Π½
90 // Π΅Π΅ Π²Π΅Ρ€Π½ΡƒΡ‚ΡŒ, Ρ‡Ρ‚ΠΎΠ±Ρ‹ Π΄Ρ€ΡƒΠ³ΠΎΠΉ ΠΎΠΆΠΈΠ΄Π°ΡŽΡ‰ΠΈΠΉ ΠΏΠΎΡ‚ΠΎΠΊ смог
91 bool hasLock = false;
94 int signals;
95 Thread.MemoryBarrier(); // m_wakeEvents volatile first read
92 96 do {
93 int signals;
94 do {
95 signals = m_wakeEvents;
96 if (signals == 0)
97 break;
98 } while (Interlocked.CompareExchange(ref m_wakeEvents, signals - 1, signals) != signals);
97 signals = m_wakeEvents;
98 if (signals == 0)
99 break;
100 } while (Interlocked.CompareExchange(ref m_wakeEvents, signals - 1, signals) != signals);
99 101
100 if (signals >= 1) {
101 if (signals > 1 && hasLock)
102 m_hasTasks.Set();
102 if (signals == 0) {
103 // no signal is fetched
104 lock(m_signalLocker) {
105 while(m_wakeEvents == 0) {
106 if (timeout != -1)
107 timeout = Math.Max(0, timeout - (Environment.TickCount - start));
108 if(!Monitor.Wait(m_signalLocker,timeout))
109 return false; // timeout
110 }
111 // m_wakeEvents > 0
112 if (Interlocked.Decrement(ref m_wakeEvents) > 0) //syncronized
113 Monitor.Pulse(m_signalLocker);
114
115 // signal fetched
103 116 return true;
104 117 }
105 118
106 if (timeout != -1)
107 timeout = Math.Max(0, timeout - (Environment.TickCount - start));
119 } else {
120 // signal fetched
121 return true;
122 }
108 123
109 // Ссли сигналов большС Π½Π΅ ΠΎΡΡ‚Π°Π»ΠΎΡΡŒ, Ρ‚ΠΎ ΠΏΠ΅Ρ€Π²Ρ‹ΠΉ ΠΏΠΎΡ‚ΠΎΠΊ, ΠΊΠΎΡ‚ΠΎΡ€Ρ‹ΠΉ дошСл сюда сбросит событиС
110 // ΠΈ ΡƒΠΉΠ΄Π΅Ρ‚ Π½Π° пустой Ρ†ΠΈΠΊΠ», послС Ρ‡Π΅Π³ΠΎ заблокируСтся
111 124
112 hasLock = true;
113 } while (m_hasTasks.WaitOne(timeout));
114
115 return false;
116 125 }
117 126
118 127 bool Sleep(int timeout) {
119 128 Interlocked.Increment(ref m_sleepingThreads);
120 129 if (FetchSignalOrWait(timeout)) {
121 130 Interlocked.Decrement(ref m_sleepingThreads);
122 131 return true;
123 132 } else {
124 133 Interlocked.Decrement(ref m_sleepingThreads);
125 134 return false;
126 135 }
127 136 }
128 137 #endregion
129 138
130 139 /// <summary>
131 140 /// ЗапускаСт Π»ΠΈΠ±ΠΎ Π½ΠΎΠ²Ρ‹ΠΉ ΠΏΠΎΡ‚ΠΎΠΊ, Ссли Ρ€Π°Π½ΡŒΡˆΠ΅ Π½Π΅ Π±Ρ‹Π»ΠΎ Π½ΠΈ ΠΎΠ΄Π½ΠΎΠ³ΠΎ ΠΏΠΎΡ‚ΠΎΠΊΠ°, Π»ΠΈΠ±ΠΎ устанавливаСт событиС ΠΏΡ€ΠΎΠ±ΡƒΠΆΠ΄Π΅Π½ΠΈΠ΅ ΠΎΠ΄Π½ΠΎΠ³ΠΎ спящСго ΠΏΠΎΡ‚ΠΎΠΊΠ°
132 141 /// </summary>
133 142 protected void GrowPool() {
134 if (m_exitRequired != 0)
143 Thread.MemoryBarrier();
144 if (m_exitRequired == 1)
135 145 return;
136 146 if (m_sleepingThreads > m_wakeEvents) {
137 147 //Console.WriteLine("Waking threads (sleeps {0}, pending {1})", m_sleepingThreads, m_wakeEvents);
138 148
139 149 // all sleeping threads may gone
140 150 SignalThread(); // wake a sleeping thread;
141 151
142 152 // we can't check whether signal has been processed
143 153 // anyway it may take some time for the thread to start
144 154 // we will ensure that at least one thread is running
145 155
146 156 EnsurePoolIsAlive();
147 157 } else {
148 158 // if there is no sleeping threads in the pool
149 159 if (!StartWorker()) {
150 160 // we haven't started a new thread, but the current can be on the way to terminate and it can't process the queue
151 161 // send it a signal to spin again
152 162 SignalThread();
153 163 EnsurePoolIsAlive();
154 164 }
155 165 }
156 166 }
157 167
158 168 protected void EnsurePoolIsAlive() {
159 169 if (AllocateThreadSlot(1)) {
160 170 // if there were no threads in the pool
161 171 var worker = new Thread(this.Worker);
162 172 worker.IsBackground = true;
163 173 worker.Start();
164 174 }
165 175 }
166 176
167 177 protected virtual bool Suspend() {
168 178 //no tasks left, exit if the thread is no longer needed
169 179 bool last;
170 180 bool requestExit;
171 181
172 182 // if threads have a timeout before releasing
173 183 if (m_releaseTimeout > 0)
174 184 requestExit = !Sleep(m_releaseTimeout);
175 185 else
176 186 requestExit = true;
177 187
178 188 if (!requestExit)
179 189 return true;
180 190
181 191 // release unsused thread
182 192 if (requestExit && ReleaseThreadSlot(out last)) {
183 193 // in case at the moment the last thread was being released
184 194 // a new task was added to the queue, we need to try
185 195 // to revoke the thread to avoid the situation when the task is left unprocessed
186 196 if (last && FetchSignalOrWait(0)) { // FetchSignalOrWait(0) will fetch pending task or will return false
187 197 SignalThread(); // since FetchSignalOrWait(0) has fetched the signal we need to reschedule it
188 198 return AllocateThreadSlot(1); // ensure that at least one thread is alive
189 199 }
190 200
191 201 return false;
192 202 }
193 203
194 204 // wait till infinity
195 205 Sleep(-1);
196 206
197 207 return true;
198 208 }
199 209
200 210 #region thread slots traits
201 211
202 212 bool AllocateThreadSlot() {
203 213 int current;
204 214 // use spins to allocate slot for the new thread
205 215 do {
206 216 current = m_createdThreads;
207 if (current >= m_maxThreads || m_exitRequired != 0)
217 if (current >= m_maxThreads || m_exitRequired == 1)
208 218 // no more slots left or the pool has been disposed
209 219 return false;
210 220 } while (current != Interlocked.CompareExchange(ref m_createdThreads, current + 1, current));
211 221
212 222 UpdateMaxThreads(current + 1);
213 223
214 224 return true;
215 225 }
216 226
217 227 bool AllocateThreadSlot(int desired) {
218 228 if (desired - 1 != Interlocked.CompareExchange(ref m_createdThreads, desired, desired - 1))
219 229 return false;
220 230
221 231 UpdateMaxThreads(desired);
222 232
223 233 return true;
224 234 }
225 235
226 236 bool ReleaseThreadSlot(out bool last) {
227 237 last = false;
228 238 int current;
229 239 // use spins to release slot for the new thread
240 Thread.MemoryBarrier();
230 241 do {
231 242 current = m_createdThreads;
232 243 if (current <= m_minThreads && m_exitRequired == 0)
233 244 // the thread is reserved
234 245 return false;
235 246 } while (current != Interlocked.CompareExchange(ref m_createdThreads, current - 1, current));
236 247
237 248 last = (current == 1);
238 249
239 250 return true;
240 251 }
241 252
242 253 /// <summary>
243 254 /// releases thread slot unconditionally, used during cleanup
244 255 /// </summary>
245 256 /// <returns>true - no more threads left</returns>
246 257 bool ReleaseThreadSlotAnyway() {
247 258 var left = Interlocked.Decrement(ref m_createdThreads);
248 259 return left == 0;
249 260 }
250 261
251 262 void UpdateMaxThreads(int count) {
252 263 int max;
253 264 do {
254 265 max = m_maxRunningThreads;
255 266 if (max >= count)
256 267 break;
257 268 } while(max != Interlocked.CompareExchange(ref m_maxRunningThreads, count, max));
258 269 }
259 270
260 271 #endregion
261 272
262 273 bool StartWorker() {
263 274 if (AllocateThreadSlot()) {
264 275 // slot successfully allocated
265 276 var worker = new Thread(this.Worker);
266 277 worker.IsBackground = true;
278 Interlocked.Increment(ref m_activeThreads);
267 279 worker.Start();
268 280
269 281 return true;
270 282 } else {
271 283 return false;
272 284 }
273 285 }
274 286
275 287 protected abstract void InvokeUnit(TUnit unit);
276 288
277 289 protected virtual void Worker() {
278 290 TUnit unit;
279 291 //Console.WriteLine("{0}: Active", Thread.CurrentThread.ManagedThreadId);
280 Interlocked.Increment(ref m_activeThreads);
292 int count = 0;;
293 Thread.MemoryBarrier();
281 294 do {
282 295 // exit if requested
283 if (m_exitRequired != 0) {
296 if (m_exitRequired == 1) {
284 297 // release the thread slot
285 298 Interlocked.Decrement(ref m_activeThreads);
286 if (ReleaseThreadSlotAnyway()) // it was the last worker
287 m_hasTasks.Dispose();
288 else
299 if (!ReleaseThreadSlotAnyway()) // it was the last worker
289 300 SignalThread(); // wake next worker
290 301 break;
291 302 }
292 303
293 304 // fetch task
294 305 if (TryDequeue(out unit)) {
295 306 InvokeUnit(unit);
307 count ++;
296 308 continue;
297 309 }
298 310 Interlocked.Decrement(ref m_activeThreads);
299 311
312 Console.WriteLine("{0}: Suspend processed({1})", Thread.CurrentThread.ManagedThreadId,count);
300 313 // entering suspend state
301 314 // keep this thread and wait
302 315 if (!Suspend())
303 316 break;
317 count = 0;
304 318 //Console.WriteLine("{0}: Awake", Thread.CurrentThread.ManagedThreadId);
305 319 Interlocked.Increment(ref m_activeThreads);
306 320 } while (true);
307 321 //Console.WriteLine("{0}: Exited", Thread.CurrentThread.ManagedThreadId);
308 322 }
309 323
310 324 protected virtual void Dispose(bool disposing) {
311 325 if (disposing) {
312 if (m_exitRequired == 0) {
313 if (Interlocked.CompareExchange(ref m_exitRequired, 1, 0) != 0)
314 return;
315
326 if (0 == Interlocked.CompareExchange(ref m_exitRequired, 1, 0)) { // implies memory barrier
316 327 // wake sleeping threads
317 328 if (m_createdThreads > 0)
318 329 SignalThread();
319 else
320 m_hasTasks.Dispose();
321 330 GC.SuppressFinalize(this);
322 331 }
323 332 }
324 333 }
325 334
326 335 public void Dispose() {
327 336 Dispose(true);
328 337 }
329 338
330 339 ~DispatchPool() {
331 340 Dispose(false);
332 341 }
333 342 }
334 343 }
@@ -1,75 +1,78
1 1 using System;
2 2 using System.Collections.Generic;
3 3 using System.Linq;
4 4 using System.Text;
5 5 using System.Threading;
6 6
7 7 namespace Implab.Parallels {
8 8 public class MTQueue<T> {
9 9 class Node {
10 10 public Node(T value) {
11 11 this.value = value;
12 12 }
13 13 public readonly T value;
14 14 public Node next;
15 15 }
16 16
17 17 Node m_first;
18 18 Node m_last;
19 19
20 20 public void Enqueue(T value) {
21 Thread.MemoryBarrier();
22
21 23 var last = m_last;
22 24 var next = new Node(value);
23 25
24 26 while (last != Interlocked.CompareExchange(ref m_last, next, last))
25 27 last = m_last;
26 28
27 29 if (last != null)
28 30 last.next = next;
29 31 else
30 32 m_first = next;
31 33 }
32 34
33 35 public bool TryDequeue(out T value) {
34 36 Node first;
35 37 Node next = null;
36 38 value = default(T);
37 39
40 Thread.MemoryBarrier();
38 41 do {
39 42 first = m_first;
40 43 if (first == null)
41 44 return false;
42 45 next = first.next;
43 46 if (next == null) {
44 47 // this is the last element,
45 48 // then try to update the tail
46 49 if (first != Interlocked.CompareExchange(ref m_last, null, first)) {
47 50 // this is the race condition
48 51 if (m_last == null)
49 52 // the queue is empty
50 53 return false;
51 54 // tail has been changed, we need to restart
52 55 continue;
53 56 }
54 57
55 58 // tail succesfully updated and first.next will never be changed
56 59 // other readers will fail due to inconsistency m_last != m_fist && m_first.next == null
57 60 // however the parallel writer may update the m_first since the m_last is null
58 61
59 62 // so we need to fix inconsistency by setting m_first to null or if it has been
60 63 // updated by the writer already then we should just to give up
61 64 Interlocked.CompareExchange(ref m_first, null, first);
62 65 break;
63 66
64 67 } else {
65 68 if (first == Interlocked.CompareExchange(ref m_first, next, first))
66 69 // head succesfully updated
67 70 break;
68 71 }
69 72 } while (true);
70 73
71 74 value = first.value;
72 75 return true;
73 76 }
74 77 }
75 78 }
@@ -1,98 +1,106
1 1 using System;
2 2 using System.Collections.Generic;
3 3 using System.Linq;
4 4 using System.Text;
5 5 using System.Threading;
6 6 using System.Diagnostics;
7 7 using Implab.Diagnostics;
8 8
9 9 namespace Implab.Parallels {
10 10 public class WorkerPool : DispatchPool<Action> {
11 11
12 12 MTQueue<Action> m_queue = new MTQueue<Action>();
13 13 int m_queueLength = 0;
14 14 readonly int m_threshold = 1;
15 int m_workers = 0;
15 16
16 17 public WorkerPool(int minThreads, int maxThreads, int threshold)
17 18 : base(minThreads, maxThreads) {
18 19 m_threshold = threshold;
20 m_workers = minThreads;
19 21 InitPool();
20 22 }
21 23
22 24 public WorkerPool(int minThreads, int maxThreads) :
23 25 base(minThreads, maxThreads) {
26 m_workers = minThreads;
24 27 InitPool();
25 28 }
26 29
27 30 public WorkerPool(int threads)
28 31 : base(threads) {
32 m_workers = threads;
29 33 InitPool();
30 34 }
31 35
32 36 public WorkerPool()
33 37 : base() {
34 38 InitPool();
35 39 }
36 40
37 41 public Promise<T> Invoke<T>(Func<T> task) {
38 42 if (task == null)
39 43 throw new ArgumentNullException("task");
40 44 if (IsDisposed)
41 45 throw new ObjectDisposedException(ToString());
42 46
43 47 var promise = new Promise<T>();
44 48
45 49 var caller = TraceContext.Snapshot();
46 50
47 51 EnqueueTask(delegate() {
48 52 caller.Invoke(delegate() {
49 53 try {
50 54 promise.Resolve(task());
51 55 } catch (Exception e) {
52 56 promise.Reject(e);
53 57 }
54 58 });
55 59 });
56 60
57 61 return promise;
58 62 }
59 63
60 64 protected void EnqueueTask(Action unit) {
61 65 Debug.Assert(unit != null);
62 66 var len = Interlocked.Increment(ref m_queueLength);
63 67 m_queue.Enqueue(unit);
64 68
65 if (len > m_threshold*ActiveThreads)
69 if (len > m_threshold * m_workers) {
70 Interlocked.Increment(ref m_workers);
66 71 GrowPool();
72 }
67 73 }
68 74
69 75 protected override bool TryDequeue(out Action unit) {
70 76 if (m_queue.TryDequeue(out unit)) {
71 77 Interlocked.Decrement(ref m_queueLength);
72 78 return true;
73 79 }
74 80 return false;
75 81 }
76 82
77 83 protected override bool Suspend() {
78 84 // This override solves race condition
79 85 // WORKER CLIENT
80 86 // ---------------------------------------
81 87 // TryDeque == false
82 88 // Enqueue(unit), queueLen++
83 89 // GrowPool? == NO
84 90 // ActiveThreads--
85 91 // Suspend
86 92 // queueLength > 0
87 93 // continue
94 Thread.MemoryBarrier();
88 95 if (m_queueLength > 0)
89 96 return true;
97 Interlocked.Decrement(ref m_workers);
90 98 return base.Suspend();
91 99 }
92 100
93 101 protected override void InvokeUnit(Action unit) {
94 102 unit();
95 103 }
96 104
97 105 }
98 106 }
@@ -1,820 +1,822
1 1 using System;
2 2 using System.Collections.Generic;
3 3 using System.Reflection;
4 4 using System.Diagnostics;
5 5 using System.Threading;
6 6 using Implab.Parallels;
7 7
8 8 namespace Implab {
9 9
10 10 public delegate void ErrorHandler(Exception e);
11 11 public delegate T ErrorHandler<out T>(Exception e);
12 12 public delegate void ResultHandler<in T>(T result);
13 13 public delegate TNew ResultMapper<in TSrc,out TNew>(TSrc result);
14 14
15 15 /// <summary>
16 16 /// Класс для асинхронного получСния Ρ€Π΅Π·ΡƒΠ»ΡŒΡ‚Π°Ρ‚ΠΎΠ². Π’Π°ΠΊ Π½Π°Π·Ρ‹Π²Π°Π΅ΠΌΠΎΠ΅ "ΠΎΠ±Π΅Ρ‰Π°Π½ΠΈΠ΅".
17 17 /// </summary>
18 18 /// <typeparam name="T">Π’ΠΈΠΏ ΠΏΠΎΠ»ΡƒΡ‡Π°Π΅ΠΌΠΎΠ³ΠΎ Ρ€Π΅Π·ΡƒΠ»ΡŒΡ‚Π°Ρ‚Π°</typeparam>
19 19 /// <remarks>
20 20 /// <para>БСрвис ΠΏΡ€ΠΈ ΠΎΠ±Ρ€Π°Ρ‰Π΅Π½ΠΈΠΈ ΠΊ Π΅Π³ΠΎ ΠΌΠ΅Ρ‚ΠΎΠ΄Ρƒ Π΄Π°Π΅Ρ‚ ΠΎΠ±Π΅Ρ‰Π°ΠΈΠ½ΠΈΠ΅ ΠΎ Π²Ρ‹ΠΏΠΎΠ»Π½Π΅Π½ΠΈΠΈ ΠΎΠΏΠ΅Ρ€Π°Ρ†ΠΈΠΈ,
21 21 /// ΠΊΠ»ΠΈΠ΅Π½Ρ‚ ΠΏΠΎΠ»ΡƒΡ‡ΠΈΠ² Ρ‚Π°ΠΊΠΎΠ΅ ΠΎΠ±Π΅Ρ‰Π°Π½ΠΈΠ΅ ΠΌΠΎΠΆΠ΅Ρ‚ ΡƒΡΡ‚Π°Π½ΠΎΠ²ΠΈΡ‚ΡŒ ряд ΠΎΠ±Ρ€Π°Ρ‚Π½Ρ‹Ρ… Π²Ρ‹Π·ΠΎΠ²ΠΎ для получСния
22 22 /// событий выполнСния обСщания, Ρ‚ΠΎΠ΅ΡΡ‚ΡŒ Π·Π°Π²Π΅Ρ€ΡˆΠ΅Π½ΠΈΡ ΠΎΠΏΠ΅Ρ€Π°Ρ†ΠΈΠΈ ΠΈ прСдоставлСнии Ρ€Π΅Π·ΡƒΠ»ΡŒΡ‚Π°Ρ‚ΠΎΠ².</para>
23 23 /// <para>
24 24 /// ΠžΠ±Π΅Ρ‰Π΅Π½ΠΈΠ΅ ΠΌΠΎΠΆΠ΅Ρ‚ Π±Ρ‹Ρ‚ΡŒ ΠΊΠ°ΠΊ Π²Ρ‹ΠΏΠΎΠ»Π½Π΅Π½ΠΎ, Ρ‚Π°ΠΊ ΠΈ Π²Ρ‹ΠΏΠΎΠ»Π½Π΅Π½ΠΎ с ошибкой. Для подписки Π½Π°
25 25 /// Π΄Π°Π½Π½Ρ‹Π΅ события ΠΊΠ»ΠΈΠ΅Π½Ρ‚ Π΄ΠΎΠ»ΠΆΠ΅Π½ ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚ΡŒ ΠΌΠ΅Ρ‚ΠΎΠ΄Ρ‹ <c>Then</c>.
26 26 /// </para>
27 27 /// <para>
28 28 /// БСрвис, Π² свою ΠΎΡ‡Π΅Ρ€Π΅Π΄ΡŒ, ΠΏΠΎ ΠΎΠΊΠΎΠ½Ρ‡Π°Π½ΠΈΡŽ выполнСния ΠΎΠΏΠ΅Ρ€Π°Ρ†ΠΈΠΈ (Π²ΠΎΠ·ΠΌΠΎΠΆΠ½ΠΎ с ошибкой),
29 29 /// ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΠ΅Ρ‚ ΠΌΠ΅Ρ‚ΠΎΠ΄Ρ‹ <c>Resolve</c> Π»ΠΈΠ±ΠΎ <c>Reject</c> для оповСщСния ΠΊΠ»ΠΈΠ΅Ρ‚Π½Π° ΠΎ
30 30 /// Π²Ρ‹ΠΏΠΎΠ»Π½Π΅Π½ΠΈΠΈ обСщания.
31 31 /// </para>
32 32 /// <para>
33 33 /// Если сСрвСр успСл Π²Ρ‹ΠΏΠΎΠ»Π½ΠΈΡ‚ΡŒ ΠΎΠ±Π΅Ρ‰Π°Π½ΠΈΠ΅ Π΅Ρ‰Π΅ Π΄ΠΎ Ρ‚ΠΎΠ³ΠΎ, ΠΊΠ°ΠΊ ΠΊΠ»ΠΈΠ΅Π½Ρ‚ Π½Π° Π½Π΅Π³ΠΎ подписался,
34 34 /// Ρ‚ΠΎ Π² ΠΌΠΎΠΌΠ΅Π½Ρ‚ подписки ΠΊΠ»ΠΈΠ΅Π½Ρ‚Π° Π±ΡƒΠ΄ΡƒΡ‚ Π²Ρ‹Π·Π²Π°Π½Ρ‹ ΡΠΎΠΎΡ‚Π²Π΅Ρ‚ΡΠ²ΡƒΡŽΡ‰ΠΈΠ΅ события Π² синхронном
35 35 /// Ρ€Π΅ΠΆΠΈΠΌΠ΅ ΠΈ ΠΊΠ»ΠΈΠ΅Π½Ρ‚ Π±ΡƒΠ΄Π΅Ρ‚ ΠΎΠΏΠΎΠ²Π΅Ρ‰Π΅Π½ Π² любом случаС. Π˜Π½Π°Ρ‡Π΅, ΠΎΠ±Ρ€Π°Π±ΠΎΡ‚Ρ‡ΠΈΠΊΠΈ Π΄ΠΎΠ±Π°Π²Π»ΡΡŽΡ‚ΡΡ Π²
36 36 /// список Π² порядкС подписания ΠΈ Π² этом ΠΆΠ΅ порядкС ΠΎΠ½ΠΈ Π±ΡƒΠ΄ΡƒΡ‚ Π²Ρ‹Π·Π²Π°Π½Ρ‹ ΠΏΡ€ΠΈ Π²Ρ‹ΠΏΠΎΠ»Π½Π΅Π½ΠΈΠΈ
37 37 /// обСщания.
38 38 /// </para>
39 39 /// <para>
40 40 /// ΠžΠ±Ρ€Π°Π±Π°Ρ‚Ρ‹Π²Π°Ρ Ρ€Π΅Π·ΡƒΠ»ΡŒΡ‚Π°Ρ‚Ρ‹ обСщания ΠΌΠΎΠΆΠ½ΠΎ ΠΏΡ€Π΅ΠΎΠ±Ρ€Π°Π·ΠΎΠ²Ρ‹Π²Π°Ρ‚ΡŒ Ρ€Π΅Π·ΡƒΠ»ΡŒΡ‚Π°Ρ‚Ρ‹ Π»ΠΈΠ±ΠΎ ΠΈΠ½ΠΈΡ†ΠΈΠΈΡ€ΠΎΠ²Π°Ρ‚ΡŒ
41 41 /// связанныС асинхронныС ΠΎΠΏΠ΅Ρ€Π°Ρ†ΠΈΠΈ, ΠΊΠΎΡ‚ΠΎΡ€Ρ‹Π΅ Ρ‚Π°ΠΊΠΆΠ΅ Π²ΠΎΠ·Π²Ρ€Π°Ρ‰Π°ΡŽΡ‚ обСщания. Для этого слСдуСт
42 42 /// ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚ΡŒ ΡΠΎΠΎΡ‚Π²Π΅Ρ‚ΡΡ‚Π²ΡƒΡŽΡ‰ΡƒΡŽ Ρ„ΠΎΡ€ΠΌΡƒ ΠΌΠ΅Ρ‚ΠΎΠ΄Π΅ <c>Then</c>.
43 43 /// </para>
44 44 /// <para>
45 45 /// Π’Π°ΠΊΠΆΠ΅ Ρ…ΠΎΡ€ΠΎΡˆΠΈΠΌ ΠΏΡ€Π°Π²ΠΈΠ»ΠΎΠΌ являСтся Ρ‚ΠΎ, Ρ‡Ρ‚ΠΎ <c>Resolve</c> ΠΈ <c>Reject</c> Π΄ΠΎΠ»ΠΆΠ΅Π½ Π²Ρ‹Π·Ρ‹Π²Π°Ρ‚ΡŒ
46 46 /// Ρ‚ΠΎΠ»ΡŒΠΊΠΎ ΠΈΠ½ΠΈΡ†ΠΈΠ°Ρ‚ΠΎΡ€ обСщания ΠΈΠ½Π°Ρ‡Π΅ ΠΌΠΎΠ³ΡƒΡ‚ Π²ΠΎΠ·Π½ΠΈΠΊΠ½ΡƒΡ‚ΡŒ противорСчия.
47 47 /// </para>
48 48 /// </remarks>
49 49 public class Promise<T> : IPromise<T> {
50 50
51 51 protected struct HandlerDescriptor {
52 52 public ResultHandler<T> resultHandler;
53 53 public ErrorHandler<T> errorHandler;
54 54 public Action cancellHandler;
55 55 public Promise<T> medium;
56 56
57 57 public void Resolve(T result) {
58 58 if (resultHandler != null) {
59 59 try {
60 60 resultHandler(result);
61 61 } catch (Exception e) {
62 62 Reject(e);
63 63 return;
64 64 }
65 65 }
66 66 if (medium != null)
67 67 medium.Resolve(result);
68 68 }
69 69
70 70 public void Reject(Exception err) {
71 71 if (errorHandler != null) {
72 72 try {
73 73 var res = errorHandler(err);
74 74 if (medium != null)
75 75 medium.Resolve(res);
76 76 } catch (TransientPromiseException err2) {
77 77 if (medium != null)
78 78 medium.Reject(err2.InnerException);
79 79 } catch (Exception err2) {
80 80 if (medium != null)
81 81 medium.Reject(err2);
82 82 }
83 83 } else if (medium != null)
84 84 medium.Reject(err);
85 85 }
86 86
87 87 public void Cancel() {
88 88 if (cancellHandler != null) {
89 89 try {
90 90 cancellHandler();
91 91 } catch (Exception err) {
92 92 Reject(err);
93 93 return;
94 94 }
95 95 }
96 96 if (medium != null)
97 97 medium.Cancel();
98 98 }
99 99 }
100 100
101 101 const int UNRESOLVED_SATE = 0;
102 102 const int TRANSITIONAL_STATE = 1;
103 103 const int SUCCEEDED_STATE = 2;
104 104 const int REJECTED_STATE = 3;
105 105 const int CANCELLED_STATE = 4;
106 106
107 107 readonly bool m_cancellable;
108 108
109 109 int m_childrenCount = 0;
110 110 int m_state;
111 111 T m_result;
112 112 Exception m_error;
113 113
114 114 readonly MTQueue<HandlerDescriptor> m_handlers = new MTQueue<HandlerDescriptor>();
115 115
116 116 public Promise() {
117 117 m_cancellable = true;
118 118 }
119 119
120 120 public Promise(IPromise parent, bool cancellable) {
121 121 m_cancellable = cancellable;
122 122 if (parent != null)
123 123 AddHandler(
124 124 null,
125 125 null,
126 126 () => {
127 127 if (parent.IsExclusive)
128 128 parent.Cancel();
129 129 },
130 130 null
131 131 );
132 132 }
133 133
134 134 bool BeginTransit() {
135 135 return UNRESOLVED_SATE == Interlocked.CompareExchange(ref m_state, TRANSITIONAL_STATE, UNRESOLVED_SATE);
136 136 }
137 137
138 138 void CompleteTransit(int state) {
139 139 if (TRANSITIONAL_STATE != Interlocked.CompareExchange(ref m_state, state, TRANSITIONAL_STATE))
140 140 throw new InvalidOperationException("Can't complete transition when the object isn't in the transitional state");
141 141 }
142 142
143 143 void WaitTransition() {
144 144 while (m_state == TRANSITIONAL_STATE) {
145 /* noop */
145 Thread.MemoryBarrier();
146 146 }
147 147 }
148 148
149 149 public bool IsResolved {
150 150 get {
151 Thread.MemoryBarrier();
151 152 return m_state > 1;
152 153 }
153 154 }
154 155
155 156 public bool IsCancelled {
156 157 get {
158 Thread.MemoryBarrier();
157 159 return m_state == CANCELLED_STATE;
158 160 }
159 161 }
160 162
161 163 public Type PromiseType {
162 164 get { return typeof(T); }
163 165 }
164 166
165 167 /// <summary>
166 168 /// ВыполняСт ΠΎΠ±Π΅Ρ‰Π°Π½ΠΈΠ΅, сообщая ΠΎΠ± ΡƒΡΠΏΠ΅ΡˆΠ½ΠΎΠΌ Π²Ρ‹ΠΏΠΎΠ»Π½Π΅Π½ΠΈΠΈ.
167 169 /// </summary>
168 170 /// <param name="result">Π Π΅Π·ΡƒΠ»ΡŒΡ‚Π°Ρ‚ выполнСния.</param>
169 171 /// <exception cref="InvalidOperationException">Π”Π°Π½Π½ΠΎΠ΅ ΠΎΠ±Π΅Ρ‰Π°Π½ΠΈΠ΅ ΡƒΠΆΠ΅ Π²Ρ‹ΠΏΠΎΠ»Π½Π΅Π½ΠΎ</exception>
170 172 public void Resolve(T result) {
171 173 if (BeginTransit()) {
172 174 m_result = result;
173 175 CompleteTransit(SUCCEEDED_STATE);
174 176 OnStateChanged();
175 177 } else {
176 178 WaitTransition();
177 179 if (m_state != CANCELLED_STATE)
178 180 throw new InvalidOperationException("The promise is already resolved");
179 181 }
180 182 }
181 183
182 184 /// <summary>
183 185 /// ВыполняСт ΠΎΠ±Π΅Ρ‰Π°Π½ΠΈΠ΅, сообщая ΠΎΠ± ΡƒΡΠΏΠ΅ΡˆΠ½ΠΎΠΌ Π²Ρ‹ΠΏΠΎΠ»Π½Π΅Π½ΠΈΠΈ. Π Π΅Π·ΡƒΠ»ΡŒΡ‚Π°Ρ‚ΠΎΠΌ выполнСния Π±ΡƒΠ΄Π΅Ρ‚ пустоС значСния.
184 186 /// </summary>
185 187 /// <remarks>
186 188 /// Π”Π°Π½Π½Ρ‹ΠΉ Π²Π°Ρ€ΠΈΠ°Π½Ρ‚ ΡƒΠ΄ΠΎΠ±Π΅Π½ Π² случаях, ΠΊΠΎΠ³Π΄Π° интСрСсСн Ρ„Π°ΠΊΡ‚ выполнСния ΠΎΠΏΠ΅Ρ€Π°Ρ†ΠΈΠΈ, Π½Π΅ΠΆΠ΅Π»ΠΈ ΠΏΠΎΠ»ΡƒΡ‡Π΅Π½Π½ΠΎΠ΅ Π·Π½Π°Ρ‡Π΅Π½ΠΈΠ΅.
187 189 /// </remarks>
188 190 public void Resolve() {
189 191 Resolve(default(T));
190 192 }
191 193
192 194 /// <summary>
193 195 /// ВыполняСт ΠΎΠ±Π΅Ρ‰Π°Π½ΠΈΠ΅, сообщая ΠΎΠ± ошибкС
194 196 /// </summary>
195 197 /// <remarks>
196 198 /// ΠŸΠΎΡΠΊΠΎΠ»ΡŒΠΊΡƒ ΠΎΠ±Π΅Ρ‰Π°Π½ΠΈΠ΅ Π΄ΠΎΠ»ΠΆΠ½ΠΎ Ρ€Π°Π±ΠΎΡ‚Π°Ρ‚ΡŒ Π² ΠΌΠ½ΠΎΠ³ΠΎΠΏΡ‚ΠΎΡ‡Π½ΠΎΠΉ срСдС, ΠΏΡ€ΠΈ Π΅Π³ΠΎ Π²Ρ‹ΠΏΠΎΠ»Π½Π΅Π½ΠΈΠΈ сразу нСсколько ΠΏΠΎΡ‚ΠΎΠΊΠΎΠ²
197 199 /// ΠΌΠΎΠ³Ρƒ Π²Π΅Ρ€Π½ΡƒΡ‚ΡŒ ΠΎΡˆΠΈΠ±ΠΊΡƒ, ΠΏΡ€ΠΈ этом Ρ‚ΠΎΠ»ΡŒΠΊΠΎ пСрвая Π±ΡƒΠ΄Π΅Ρ‚ использована Π² качСствС Ρ€Π΅Π·ΡƒΠ»ΡŒΡ‚Π°Ρ‚Π°, ΠΎΡΡ‚Π°Π»ΡŒΠ½Ρ‹Π΅
198 200 /// Π±ΡƒΠ΄ΡƒΡ‚ ΠΏΡ€ΠΎΠΈΠ³Π½ΠΎΡ€ΠΈΡ€ΠΎΠ²Π°Π½Ρ‹.
199 201 /// </remarks>
200 202 /// <param name="error">Π˜ΡΠΊΠ»ΡŽΡ‡Π΅Π½ΠΈΠ΅ возникшСС ΠΏΡ€ΠΈ Π²Ρ‹ΠΏΠΎΠ»Π½Π΅Π½ΠΈΠΈ ΠΎΠΏΠ΅Ρ€Π°Ρ†ΠΈΠΈ</param>
201 203 /// <exception cref="InvalidOperationException">Π”Π°Π½Π½ΠΎΠ΅ ΠΎΠ±Π΅Ρ‰Π°Π½ΠΈΠ΅ ΡƒΠΆΠ΅ Π²Ρ‹ΠΏΠΎΠ»Π½Π΅Π½ΠΎ</exception>
202 204 public void Reject(Exception error) {
203 205 if (BeginTransit()) {
204 206 m_error = error;
205 207 CompleteTransit(REJECTED_STATE);
206 208 OnStateChanged();
207 209 } else {
208 210 WaitTransition();
209 211 if (m_state == SUCCEEDED_STATE)
210 212 throw new InvalidOperationException("The promise is already resolved");
211 213 }
212 214 }
213 215
214 216 /// <summary>
215 217 /// ΠžΡ‚ΠΌΠ΅Π½ΡΠ΅Ρ‚ ΠΎΠΏΠ΅Ρ€Π°Ρ†ΠΈΡŽ, Ссли это Π²ΠΎΠ·ΠΌΠΎΠΆΠ½ΠΎ.
216 218 /// </summary>
217 219 /// <remarks>Для опрСдСлСния Π±Ρ‹Π»Π° Π»ΠΈ опСрация ΠΎΡ‚ΠΌΠ΅Π½Π΅Π½Π° слСдуСт ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚ΡŒ свойство <see cref="IsCancelled"/>.</remarks>
218 220 public void Cancel() {
219 221 if (m_cancellable && BeginTransit()) {
220 222 CompleteTransit(CANCELLED_STATE);
221 223 OnStateChanged();
222 224 }
223 225 }
224 226
225 227 public IPromise<T> Then(ResultHandler<T> success, ErrorHandler<T> error, Action cancel) {
226 228 if (success == null && error == null && cancel == null)
227 229 return this;
228 230
229 231 var medium = new Promise<T>(this, true);
230 232
231 233 AddHandler(success, error, cancel, medium);
232 234
233 235 return medium;
234 236 }
235 237
236 238 /// <summary>
237 239 /// Adds new handlers to this promise.
238 240 /// </summary>
239 241 /// <param name="success">The handler of the successfully completed operation.
240 242 /// This handler will recieve an operation result as a parameter.</param>
241 243 /// <param name="error">Handles an exception that may occur during the operation and returns the value which will be used as the result of the operation.</param>
242 244 /// <returns>The new promise chained to this one.</returns>
243 245 public IPromise<T> Then(ResultHandler<T> success, ErrorHandler<T> error) {
244 246 if (success == null && error == null)
245 247 return this;
246 248
247 249 var medium = new Promise<T>(this, true);
248 250
249 251 AddHandler(success, error, null, medium);
250 252
251 253 return medium;
252 254 }
253 255
254 256
255 257
256 258
257 259 public IPromise<T> Then(ResultHandler<T> success) {
258 260 if (success == null)
259 261 return this;
260 262
261 263 var medium = new Promise<T>(this, true);
262 264
263 265 AddHandler(success, null, null, medium);
264 266
265 267 return medium;
266 268 }
267 269
268 270 /// <summary>
269 271 /// ПослСдний ΠΎΠ±Ρ€Π°Π±ΠΎΡ‚Ρ‡ΠΈΠΊ Π² Ρ†Π΅ΠΏΠΎΡ‡ΠΊΠΈ ΠΎΠ±Π΅Ρ‰Π°Π½ΠΈΠΉ.
270 272 /// </summary>
271 273 /// <param name="success"></param>
272 274 /// <param name="error"></param>
273 275 /// <param name="cancel"></param>
274 276 /// <remarks>
275 277 /// <para>
276 278 /// Π”Π°Π½Π½Ρ‹ΠΉ ΠΌΠ΅Ρ‚ΠΎΠ΄ Π½Π΅ создаСт связанного с Ρ‚Π΅ΠΊΡƒΡ‰ΠΈΠΌ обСщания ΠΈ ΠΏΡ€Π΅Π΄Π½Π°Π·Π½Π°Ρ‡Π΅Π½ для окончания
277 279 /// фсинхронной Ρ†Π΅ΠΏΠΎΡ‡ΠΊΠΈ.
278 280 /// </para>
279 281 /// <para>
280 282 /// Если Π΄Π°Π½Π½Ρ‹ΠΉ ΠΌΠ΅Ρ‚ΠΎΠ΄ Π²Ρ‹Π·Π²Π°Ρ‚ΡŒ нСсколько Ρ€Π°Π·, Π»ΠΈΠ±ΠΎ Π΄ΠΎΠ±Π°Π²ΠΈΡ‚ΡŒ Π΄Ρ€ΡƒΠ³ΠΈΠ΅ ΠΎΠ±Ρ€Π°Π±ΠΎΡ‚Ρ‡ΠΈΠΊΠΈ, Ρ‚ΠΎ Ρ†Π΅ΠΏΠΎΡ‡ΠΊΠ°
281 283 /// Π½Π΅ Π±ΡƒΠ΄Π΅Ρ‚ ΠΎΠ΄ΠΈΠ½ΠΎΡ‡Π½ΠΎΠΉ <see cref="IsExclusive"/> ΠΈ, ΠΊΠ°ΠΊ слСдствиС, Π±ΡƒΠ΄Π΅Ρ‚ Π½Π΅Π²ΠΎΠ·ΠΌΠΎΠΆΠ½Π° ΠΎΡ‚ΠΌΠ΅Π½Π°
282 284 /// всСй Ρ†Π΅ΠΏΠΈ ΠΎΠ±Π΅Ρ‰Π°Π½ΠΈΠΉ снизу (с самого послСднСго обСщания).
283 285 /// </para>
284 286 /// </remarks>
285 287 public void Last(ResultHandler<T> success, ErrorHandler error, Action cancel) {
286 288 if (success == null && error == null && cancel == null)
287 289 return;
288 290
289 291 ErrorHandler<T> errorHandler = null;
290 292 if (error != null)
291 293 errorHandler = err => {
292 294 error(err);
293 295 return default(T);
294 296 };
295 297 AddHandler(success, errorHandler, cancel, null);
296 298 }
297 299
298 300 public void Last(ResultHandler<T> success, ErrorHandler error) {
299 301 Last(success, error, null);
300 302 }
301 303
302 304 public void Last(ResultHandler<T> success) {
303 305 Last(success, null, null);
304 306 }
305 307
306 308 public IPromise Error(ErrorHandler error) {
307 309 if (error == null)
308 310 return this;
309 311
310 312 var medium = new Promise<T>(this, true);
311 313
312 314 AddHandler(
313 315 null,
314 316 e => {
315 317 error(e);
316 318 return default(T);
317 319 },
318 320 null,
319 321 medium
320 322 );
321 323
322 324 return medium;
323 325 }
324 326
325 327 /// <summary>
326 328 /// Handles error and allows to keep the promise.
327 329 /// </summary>
328 330 /// <remarks>
329 331 /// If the specified handler throws an exception, this exception will be used to reject the promise.
330 332 /// </remarks>
331 333 /// <param name="handler">The error handler which returns the result of the promise.</param>
332 334 /// <returns>New promise.</returns>
333 335 public IPromise<T> Error(ErrorHandler<T> handler) {
334 336 if (handler == null)
335 337 return this;
336 338
337 339 var medium = new Promise<T>(this, true);
338 340
339 341 AddHandler(null, handler, null, medium);
340 342
341 343 return medium;
342 344 }
343 345
344 346 /// <summary>
345 347 /// ΠŸΠΎΠ·Π²ΠΎΠ»ΡΠ΅Ρ‚ ΠΏΡ€Π΅ΠΎΠ±Ρ€Π°Π·ΠΎΠ²Π°Ρ‚ΡŒ Ρ€Π΅Π·ΡƒΠ»ΡŒΡ‚Π°Ρ‚ выполСния ΠΎΠΏΠ΅Ρ€Π°Ρ†ΠΈΠΈ ΠΊ Π½ΠΎΠ²ΠΎΠΌΡƒ Ρ‚ΠΈΠΏΡƒ.
346 348 /// </summary>
347 349 /// <typeparam name="TNew">Новый Ρ‚ΠΈΠΏ Ρ€Π΅Π·ΡƒΠ»ΡŒΡ‚Π°Ρ‚Π°.</typeparam>
348 350 /// <param name="mapper">ΠŸΡ€Π΅ΠΎΠ±Ρ€Π°Π·ΠΎΠ²Π°Π½ΠΈΠ΅ Ρ€Π΅Π·ΡƒΠ»ΡŒΡ‚Π°Ρ‚Π° ΠΊ Π½ΠΎΠ²ΠΎΠΌΡƒ Ρ‚ΠΈΠΏΡƒ.</param>
349 351 /// <param name="error">ΠžΠ±Ρ€Π°Π±ΠΎΡ‚Ρ‡ΠΈΠΊ ошибки. Π”Π°Π½Π½Ρ‹ΠΉ ΠΎΠ±Ρ€Π°Π±ΠΎΡ‚Ρ‡ΠΈΠΊ ΠΏΠΎΠ»ΡƒΡ‡ΠΈΡ‚
350 352 /// ΠΈΡΠΊΠ»ΡŽΡ‡Π΅Π½ΠΈΠ΅ возникшСС ΠΏΡ€ΠΈ Π²Ρ‹ΠΏΠΎΠ»Π½Π΅Π½ΠΈΠΈ ΠΎΠΏΠ΅Ρ€Π°Ρ†ΠΈΠΈ.</param>
351 353 /// <returns>НовоС ΠΎΠ±Π΅Ρ‰Π°Π½ΠΈΠ΅, ΠΊΠΎΡ‚ΠΎΡ€ΠΎΠ΅ Π±ΡƒΠ΄Π΅Ρ‚ Π²Ρ‹ΠΏΠΎΠ»Π½Π΅Π½ΠΎ ΠΏΡ€ΠΈ Π²Ρ‹ΠΏΠΎΠ»Π½Π΅Π½ΠΈΠΈ исходного обСщания.</returns>
352 354 public IPromise<TNew> Then<TNew>(ResultMapper<T, TNew> mapper, ErrorHandler<TNew> error, Action cancel) {
353 355 Safe.ArgumentNotNull(mapper, "mapper");
354 356
355 357 // создаСм ΠΏΡ€ΠΈΡ†Π΅ΠΏΠ»Π΅Π½Π½ΠΎΠ΅ ΠΎΠ±Π΅Ρ‰Π°Π½ΠΈΠ΅
356 358 var medium = new Promise<TNew>(this, true);
357 359
358 360 ResultHandler<T> resultHandler = result => medium.Resolve(mapper(result));
359 361 ErrorHandler<T> errorHandler;
360 362 if (error != null)
361 363 errorHandler = e => {
362 364 try {
363 365 medium.Resolve(error(e));
364 366 } catch (Exception e2) {
365 367 // Π² случаС ошибки Π½ΡƒΠΆΠ½ΠΎ ΠΏΠ΅Ρ€Π΅Π΄Π°Ρ‚ΡŒ ΠΈΡΠΊΠ»ΡŽΡ‡Π΅Π½ΠΈΠ΅ дальшС ΠΏΠΎ Ρ†Π΅ΠΏΠΎΡ‡ΠΊΠ΅
366 368 medium.Reject(e2);
367 369 }
368 370 return default(T);
369 371 };
370 372 else
371 373 errorHandler = e => {
372 374 medium.Reject(e);
373 375 return default(T);
374 376 };
375 377
376 378 Action cancelHandler;
377 379 if (cancel != null)
378 380 cancelHandler = () => {
379 381 cancel();
380 382 medium.Cancel();
381 383 };
382 384 else
383 385 cancelHandler = medium.Cancel;
384 386
385 387
386 388 AddHandler(
387 389 resultHandler,
388 390 errorHandler,
389 391 cancelHandler,
390 392 null
391 393 );
392 394
393 395 return medium;
394 396 }
395 397
396 398 public IPromise<TNew> Then<TNew>(ResultMapper<T, TNew> mapper, ErrorHandler<TNew> error) {
397 399 return Then(mapper, error, null);
398 400 }
399 401
400 402 public IPromise<TNew> Then<TNew>(ResultMapper<T, TNew> mapper) {
401 403 return Then(mapper, null, null);
402 404 }
403 405
404 406 /// <summary>
405 407 /// БцСпляСт нСсколько аснхронных ΠΎΠΏΠ΅Ρ€Π°Ρ†ΠΈΠΉ. Указанная асинхронная опСрация Π±ΡƒΠ΄Π΅Ρ‚ Π²Ρ‹Π·Π²Π°Π½Π° послС
406 408 /// выполнСния Ρ‚Π΅ΠΊΡƒΡ‰Π΅ΠΉ, Π° Ρ€Π΅Π·ΡƒΠ»ΡŒΡ‚Π°Ρ‚ Ρ‚Π΅ΠΊΡƒΡ‰Π΅ΠΉ ΠΎΠΏΠ΅Ρ€Π°Ρ†ΠΈΠΈ ΠΌΠΎΠΆΠ΅Ρ‚ Π±Ρ‹Ρ‚ΡŒ использован для ΠΈΠ½ΠΈΡ†ΠΈΠ°Π»ΠΈΠ·Π°Ρ†ΠΈΠΈ
407 409 /// Π½ΠΎΠ²ΠΎΠΉ ΠΎΠΏΠ΅Ρ€Π°Ρ†ΠΈΠΈ.
408 410 /// </summary>
409 411 /// <typeparam name="TNew">Π’ΠΈΠΏ Ρ€Π΅Π·ΡƒΠ»ΡŒΡ‚Π°Ρ‚Π° ΡƒΠΊΠ°Π·Π°Π½Π½ΠΎΠΉ асинхронной ΠΎΠΏΠ΅Ρ€Π°Ρ†ΠΈΠΈ.</typeparam>
410 412 /// <param name="chained">Асинхронная опСрация, которая Π΄ΠΎΠ»ΠΆΠ½Π° Π±ΡƒΠ΄Π΅Ρ‚ Π½Π°Ρ‡Π°Ρ‚ΡŒΡΡ послС выполнСния Ρ‚Π΅ΠΊΡƒΡ‰Π΅ΠΉ.</param>
411 413 /// <param name="error">ΠžΠ±Ρ€Π°Π±ΠΎΡ‚Ρ‡ΠΈΠΊ ошибки. Π”Π°Π½Π½Ρ‹ΠΉ ΠΎΠ±Ρ€Π°Π±ΠΎΡ‚Ρ‡ΠΈΠΊ ΠΏΠΎΠ»ΡƒΡ‡ΠΈΡ‚
412 414 /// ΠΈΡΠΊΠ»ΡŽΡ‡Π΅Π½ΠΈΠ΅ возникшСС ΠΏΡ€ΠΈ Π²Ρ‹ΠΏΠΎΠ»Π½Π΅Π½ΠΈΠΈ Ρ‚Π΅ΠΊΡƒΠ΅Ρ‰ΠΉ ΠΎΠΏΠ΅Ρ€Π°Ρ†ΠΈΠΈ.</param>
413 415 /// <returns>НовоС ΠΎΠ±Π΅Ρ‰Π°Π½ΠΈΠ΅, ΠΊΠΎΡ‚ΠΎΡ€ΠΎΠ΅ Π±ΡƒΠ΄Π΅Ρ‚ Π²Ρ‹ΠΏΠΎΠ»Π½Π΅Π½ΠΎ ΠΏΠΎ ΠΎΠΊΠΎΠ½Ρ‡Π°Π½ΠΈΡŽ ΡƒΠΊΠ°Π·Π°Π½Π½ΠΎΠΉ аснхронной ΠΎΠΏΠ΅Ρ€Π°Ρ†ΠΈΠΈ.</returns>
414 416 public IPromise<TNew> Chain<TNew>(ResultMapper<T, IPromise<TNew>> chained, ErrorHandler<IPromise<TNew>> error, Action cancel) {
415 417
416 418 Safe.ArgumentNotNull(chained, "chained");
417 419
418 420 // ΠΏΡ€ΠΎΠ±Π»Π΅ΠΌΠ° Π² Ρ‚ΠΎΠΌ, Ρ‡Ρ‚ΠΎ Π½Π° ΠΌΠΎΠΌΠ΅Π½Ρ‚ связывания Π΅Ρ‰Π΅ Π½Π΅ Π½Π°Ρ‡Π°Ρ‚Π° асинхронная опСрация, поэтому Π½ΡƒΠΆΠ½ΠΎ
419 421 // ΡΠΎΠ·Π΄Π°Ρ‚ΡŒ посрСдника, ΠΊ ΠΊΠΎΡ‚ΠΎΡ€ΠΎΠΌΡƒ Π±ΡƒΠ΄ΡƒΡ‚ ΠΏΠΎΠ΄Π²Ρ‹Π·ΡΠ²Π°Ρ‚ΡŒΡΡ ΡΠ»Π΅Π΄ΡƒΡŽΡ‰ΠΈΠ΅ ΠΎΠ±Ρ€Π°Π±ΠΎΡ‚Ρ‡ΠΈΠΊΠΈ.
420 422 // ΠΊΠΎΠ³Π΄Π° Π±ΡƒΠ΄Π΅Ρ‚ Π²Ρ‹ΠΏΠΎΠ»Π½Π΅Π½Π° Ρ€Π΅Π°Π»ΡŒΠ½Π°Ρ асинхронная опСрация, ΠΎΠ½Π° ΠΎΠ±Ρ€Π°Ρ‚ΠΈΡ‚ΡŒΡΡ ΠΊ посрСднику, Ρ‡Ρ‚ΠΎΠ±Ρ‹
421 423 // ΠΏΠ΅Ρ€Π΅Π΄Π°Ρ‚ΡŒ Ρ‡Π΅Ρ€Π΅Π· Π½Π΅Π³ΠΎ Ρ€Π΅Π·ΡƒΠ»ΡŒΡ‚Π°Ρ‚Ρ‹ Ρ€Π°Π±ΠΎΡ‚Ρ‹.
422 424 var medium = new Promise<TNew>(this, true);
423 425
424 426 ResultHandler<T> resultHandler = delegate(T result) {
425 427 if (medium.IsCancelled)
426 428 return;
427 429
428 430 var promise = chained(result);
429 431
430 432 promise.Last(
431 433 medium.Resolve,
432 434 medium.Reject,
433 435 () => medium.Reject(new OperationCanceledException()) // внСшняя ΠΎΡ‚ΠΌΠ΅Π½Π° связанной ΠΎΠΏΠ΅Ρ€Π°Ρ†ΠΈΠΈ рассматриваСтся ΠΊΠ°ΠΊ ошибка
434 436 );
435 437
436 438 // notify chained operation that it's not needed anymore
437 439 // порядок Π²Ρ‹Π·ΠΎΠ²Π° Then, Cancelled Π²Π°ΠΆΠ΅Π½, ΠΏΠΎΡΠΊΠΎΠ»ΡŒΠΊΡƒ ΠΎΡ‚ этого
438 440 // зависит IsExclusive
439 441 medium.Cancelled(() => {
440 442 if (promise.IsExclusive)
441 443 promise.Cancel();
442 444 });
443 445 };
444 446
445 447 ErrorHandler<T> errorHandler;
446 448
447 449 if (error != null)
448 450 errorHandler = delegate(Exception e) {
449 451 try {
450 452 var promise = error(e);
451 453
452 454 promise.Last(
453 455 medium.Resolve,
454 456 medium.Reject,
455 457 () => medium.Reject(new OperationCanceledException()) // внСшняя ΠΎΡ‚ΠΌΠ΅Π½Π° связанной ΠΎΠΏΠ΅Ρ€Π°Ρ†ΠΈΠΈ рассматриваСтся ΠΊΠ°ΠΊ ошибка
456 458 );
457 459
458 460 // notify chained operation that it's not needed anymore
459 461 // порядок Π²Ρ‹Π·ΠΎΠ²Π° Then, Cancelled Π²Π°ΠΆΠ΅Π½, ΠΏΠΎΡΠΊΠΎΠ»ΡŒΠΊΡƒ ΠΎΡ‚ этого
460 462 // зависит IsExclusive
461 463 medium.Cancelled(() => {
462 464 if (promise.IsExclusive)
463 465 promise.Cancel();
464 466 });
465 467 } catch (Exception e2) {
466 468 medium.Reject(e2);
467 469 }
468 470 return default(T);
469 471 };
470 472 else
471 473 errorHandler = err => {
472 474 medium.Reject(err);
473 475 return default(T);
474 476 };
475 477
476 478
477 479 Action cancelHandler;
478 480 if (cancel != null)
479 481 cancelHandler = () => {
480 482 if (cancel != null)
481 483 cancel();
482 484 medium.Cancel();
483 485 };
484 486 else
485 487 cancelHandler = medium.Cancel;
486 488
487 489 AddHandler(
488 490 resultHandler,
489 491 errorHandler,
490 492 cancelHandler,
491 493 null
492 494 );
493 495
494 496 return medium;
495 497 }
496 498
497 499 public IPromise<TNew> Chain<TNew>(ResultMapper<T, IPromise<TNew>> chained, ErrorHandler<IPromise<TNew>> error) {
498 500 return Chain(chained, error, null);
499 501 }
500 502
501 503 public IPromise<TNew> Chain<TNew>(ResultMapper<T, IPromise<TNew>> chained) {
502 504 return Chain(chained, null, null);
503 505 }
504 506
505 507 public IPromise<T> Cancelled(Action handler) {
506 508 var medium = new Promise<T>(this,true);
507 509 AddHandler(null, null, handler, medium);
508 510 return medium;
509 511 }
510 512
511 513 /// <summary>
512 514 /// Adds the specified handler for all cases (success, error, cancel)
513 515 /// </summary>
514 516 /// <param name="handler">The handler that will be called anyway</param>
515 517 /// <returns>self</returns>
516 518 public IPromise<T> Anyway(Action handler) {
517 519 Safe.ArgumentNotNull(handler, "handler");
518 520
519 521 AddHandler(
520 522 x => handler(),
521 523 e => {
522 524 handler();
523 525 throw new TransientPromiseException(e);
524 526 },
525 527 handler,
526 528 null
527 529 );
528 530 return this;
529 531 }
530 532
531 533 /// <summary>
532 534 /// ΠŸΡ€Π΅ΠΎΠ±Ρ€Π°Π·ΡƒΠ΅Ρ‚ Ρ€Π΅Π·ΡƒΠ»ΡŒΡ‚Π°Ρ‚ обСщания ΠΊ Π½ΡƒΠΆΠ½ΠΎΠΌΡƒ Ρ‚ΠΈΠΏΡƒ
533 535 /// </summary>
534 536 /// <typeparam name="T2"></typeparam>
535 537 /// <returns></returns>
536 538 public IPromise<T2> Cast<T2>() {
537 539 return Then(x => (T2)(object)x, null);
538 540 }
539 541
540 542 /// <summary>
541 543 /// ДоТидаСтся ΠΎΡ‚Π»ΠΎΠΆΠ΅Π½Π½ΠΎΠ³ΠΎ обСщания ΠΈ Π² случаС успСха, Π²ΠΎΠ·Π²Ρ€Π°Ρ‰Π°Π΅Ρ‚
542 544 /// Π΅Π³ΠΎ, Ρ€Π΅Π·ΡƒΠ»ΡŒΡ‚Π°Ρ‚, Π² ΠΏΡ€ΠΎΡ‚ΠΈΠ²Π½ΠΎΠΌ случаС бросаСт ΠΈΡΠΊΠ»ΡŽΡ‡Π΅Π½ΠΈΠ΅.
543 545 /// </summary>
544 546 /// <remarks>
545 547 /// <para>
546 548 /// Если ΠΎΠΆΠΈΠ΄Π°Π½ΠΈΠ΅ обСщания Π±Ρ‹Π»ΠΎ ΠΏΡ€Π΅Ρ€Π²Π°Π½ΠΎ ΠΏΠΎ Ρ‚Π°ΠΉΠΌΠ°ΡƒΡ‚Ρƒ, это Π½Π΅ Π·Π½Π°Ρ‡ΠΈΡ‚,
547 549 /// Ρ‡Ρ‚ΠΎ ΠΎΠ±Π΅Ρ‰Π°Π½ΠΈΠ΅ Π±Ρ‹Π»ΠΎ ΠΎΡ‚ΠΌΠ΅Π½Π΅Π½ΠΎ ΠΈΠ»ΠΈ Ρ‡Ρ‚ΠΎ-Ρ‚ΠΎ Π² этом Ρ€ΠΎΠ΄Π΅, это Ρ‚ΠΎΠ»ΡŒΠΊΠΎ
548 550 /// ΠΎΠ·Π½Π°Ρ‡Π°Π΅Ρ‚, Ρ‡Ρ‚ΠΎ ΠΌΡ‹ Π΅Π³ΠΎ Π½Π΅ доТдались, ΠΎΠ΄Π½Π°ΠΊΠΎ всС зарСгистрированныС
549 551 /// ΠΎΠ±Ρ€Π°Π±ΠΎΡ‚Ρ‡ΠΈΠΊΠΈ, ΠΊΠ°ΠΊ Π±Ρ‹Π»ΠΈ Ρ‚Π°ΠΊ ΠΎΡΡ‚Π°Π»ΠΈΡΡŒ ΠΈ ΠΎΠ½ΠΈ Π±ΡƒΠ΄ΡƒΡ‚ Π²Ρ‹Π·Π²Π°Π½Ρ‹, ΠΊΠΎΠ³Π΄Π°
550 552 /// ΠΎΠ±Π΅Ρ‰Π°Π½ΠΈΠ΅ Π±ΡƒΠ΄Π΅Ρ‚ Π²Ρ‹ΠΏΠΎΠ»Π½Π΅Π½ΠΎ.
551 553 /// </para>
552 554 /// <para>
553 555 /// Π’Π°ΠΊΠΎΠ΅ ΠΏΠΎΠ²Π΅Π΄Π΅Π½ΠΈΠ΅ Π²ΠΏΠΎΠ»Π½Π΅ ΠΎΠΏΡ€Π°Π²Π΄Π°Π½ΠΎ ΠΏΠΎΡΠΊΠΎΠ»ΡŒΠΊΡƒ Ρ‚Π°ΠΉΠΌΠ°ΡƒΡ‚ ΠΌΠΎΠΆΠ΅Ρ‚ ΠΈΡΡ‚Π΅Ρ‡ΡŒ
554 556 /// Π² Ρ‚ΠΎΡ‚ ΠΌΠΎΠΌΠ΅Π½Ρ‚, ΠΊΠΎΠ³Π΄Π° Π½Π°Ρ‡Π°Π»Π°ΡΡŒ ΠΎΠ±Ρ€Π°Π±ΠΎΡ‚ΠΊΠ° Ρ†Π΅ΠΏΠΎΡ‡ΠΊΠΈ ΠΎΠ±Ρ€Π°Π±ΠΎΡ‚Ρ‡ΠΈΠΊΠΎΠ², ΠΈ
555 557 /// ΠΊ Ρ‚ΠΎΠΌΡƒ ΠΆΠ΅ Ρ‚Π΅ΠΊΡƒΡ‰Π΅Π΅ ΠΎΠ±Π΅Ρ‰Π°Π½ΠΈΠ΅ ΠΌΠΎΠΆΠ΅Ρ‚ ΡΡ‚ΠΎΡΡ‚ΡŒ Π² Ρ†Π΅ΠΏΠΎΡ‡ΠΊΠ΅ ΠΎΠ±Π΅Ρ‰Π°Π½ΠΈΠΉ ΠΈ Π΅Π³ΠΎ
556 558 /// ΠΎΡ‚ΠΊΠ»ΠΎΠ½Π΅Π½ΠΈΠ΅ ΠΌΠΎΠΆΠ΅Ρ‚ привСсти ΠΊ Π½Π΅ΠΏΡ€ΠΎΠ³Π½ΠΎΠ·ΠΈΡ€ΡƒΠ΅ΠΌΠΎΠΌΡƒ Ρ€Π΅Π·ΡƒΠ»ΡŒΡ‚Π°Ρ‚Ρƒ.
557 559 /// </para>
558 560 /// </remarks>
559 561 /// <param name="timeout">ВрСмя оТидания</param>
560 562 /// <returns>Π Π΅Π·ΡƒΠ»ΡŒΡ‚Π°Ρ‚ выполнСния обСщания</returns>
561 563 public T Join(int timeout) {
562 564 var evt = new ManualResetEvent(false);
563 565 Anyway(() => evt.Set());
564 566
565 567 if (!evt.WaitOne(timeout, true))
566 568 throw new TimeoutException();
567 569
568 570 switch (m_state) {
569 571 case SUCCEEDED_STATE:
570 572 return m_result;
571 573 case CANCELLED_STATE:
572 574 throw new OperationCanceledException();
573 575 case REJECTED_STATE:
574 576 throw new TargetInvocationException(m_error);
575 577 default:
576 578 throw new ApplicationException(String.Format("Invalid promise state {0}", m_state));
577 579 }
578 580 }
579 581
580 582 public T Join() {
581 583 return Join(Timeout.Infinite);
582 584 }
583 585
584 586 void AddHandler(ResultHandler<T> success, ErrorHandler<T> error, Action cancel, Promise<T> medium) {
585 587 if (success != null || error != null)
586 588 Interlocked.Increment(ref m_childrenCount);
587 589
588 590 var handler = new HandlerDescriptor {
589 591 resultHandler = success,
590 592 errorHandler = error,
591 593 cancellHandler = cancel,
592 594 medium = medium
593 595 };
594 596
595 597 bool queued;
596 598
597 599 if (!IsResolved) {
598 600 m_handlers.Enqueue(handler);
599 601 queued = true;
600 602 } else {
601 603 // the promise is in resolved state, just invoke the handled with minimum overhead
602 604 queued = false;
603 605 InvokeHandler(handler);
604 606 }
605 607
606 608 if (queued && IsResolved && m_handlers.TryDequeue(out handler))
607 609 // if the promise have been resolved while we was adding handler to the queue
608 610 // we can't guarantee that someone is still processing it
609 611 // therefore we will fetch a handler from the queue and execute it
610 612 // note that fetched handler may be not the one that we have added
611 613 // even we can fetch no handlers at all :)
612 614 InvokeHandler(handler);
613 615 }
614 616
615 617 protected virtual void InvokeHandler(HandlerDescriptor handler) {
616 618 switch (m_state) {
617 619 case SUCCEEDED_STATE:
618 620 handler.Resolve(m_result);
619 621 break;
620 622 case REJECTED_STATE:
621 623 handler.Reject(m_error);
622 624 break;
623 625 case CANCELLED_STATE:
624 626 handler.Cancel();
625 627 break;
626 628 default:
627 629 // do nothing
628 630 return;
629 631 }
630 632 }
631 633
632 634 void OnStateChanged() {
633 635 HandlerDescriptor handler;
634 636 while (m_handlers.TryDequeue(out handler))
635 637 InvokeHandler(handler);
636 638 }
637 639
638 640 public bool IsExclusive {
639 641 get {
640 642 return m_childrenCount <= 1;
641 643 }
642 644 }
643 645
644 646 /// <summary>
645 647 /// ΠžΠ±ΡŠΠ΅Π΄ΠΈΠ½ΡΠ΅Ρ‚ нСсколько ΠΎΠ±Π΅Ρ‰Π°Π½ΠΈΠΉ Π² ΠΎΠ΄Π½ΠΎ, Ρ€Π΅Π·ΡƒΠ»ΡŒΡ‚Π°Ρ‚ΠΎΠΌ ΠΊΠΎΡ‚ΠΎΡ€ΠΎΠ³ΠΎ являСтся массив Ρ€Π΅Π·ΡƒΠ»ΡŒΡ‚Π°Ρ‚ΠΎΠ² Π΄Ρ€ΡƒΠ³ΠΈΡ… ΠΎΠ±Π΅Ρ‰Π°Π½ΠΈΠΉ.
646 648 /// Если хотябы ΠΎΠ΄Π½ΠΎ ΠΈΠ· ΠΏΠ΅Ρ€Π΅Π΄Π°Π½Π½Ρ‹Ρ… ΠΎΠ±Π΅Ρ‰Π°Π½ΠΈΠΉ Π½Π΅ Π±ΡƒΠ΄Π΅Ρ‚ Π²Ρ‹ΠΏΠΎΠ»Π½Π΅Π½ΠΎ, Ρ‚ΠΎ Π½ΠΎΠ²ΠΎΠ΅ ΠΎΠ±Π΅Ρ‰Π΅Π½ΠΈΠ΅ Ρ‚ΠΎΠΆΠ΅ Π½Π΅ Π±ΡƒΠ΄Π΅Ρ‚ Π²Ρ‹ΠΏΠΎΠ»Π½Π΅Π½ΠΎ.
647 649 /// ΠŸΡ€ΠΈ ΠΎΡ‚ΠΌΠ΅Π½Π΅ Π½ΠΎΠ²ΠΎΠ³ΠΎ обСщания, ΠΏΠ΅Ρ€Π΅Π΄Π°Π½Π½Ρ‹Π΅ обСщания Ρ‚Π°ΠΊΠΆΠ΅ Π±ΡƒΠ΄ΡƒΡ‚ ΠΎΡ‚ΠΌΠ΅Π½Π΅Π½Ρ‹, Ссли Π½ΠΈΠΊΡ‚ΠΎ большС Π½Π° Π½ΠΈΡ… Π½Π΅ подписан.
648 650 /// </summary>
649 651 /// <param name="promises">Бписок ΠΎΠ±Π΅Ρ‰Π°Π½ΠΈΠΉ. Если список пустой, Ρ‚ΠΎ Ρ€Π΅Π·ΡƒΠ»ΡŒΡ‚ΠΈΡ€ΡƒΡŽΡ‰Π΅Π΅ ΠΎΠ±Π΅Ρ‰Π°Π½ΠΈΠ΅ возвращаСтся ΡƒΠΆΠ΅ Π²Ρ‹ΠΏΠΎΠ»Π½Π΅Π½Π½Ρ‹ΠΌ.</param>
650 652 /// <returns>ΠžΠ±Π΅Ρ‰Π°Π½ΠΈΠ΅ ΠΎΠ±ΡŠΠ΅Π΄ΠΈΠ½ΡΡŽΡ‰Π΅Π΅ Π² сСбС Ρ€Π΅Π·ΡƒΠ»ΡŒΡ‚Π°Ρ‚ ΠΏΠ΅Ρ€Π΅Π΄Π°Π½Π½Ρ‹Ρ… ΠΎΠ±Π΅Ρ‰Π°Π½ΠΈΠΉ.</returns>
651 653 /// <exception cref="ArgumentNullException"><paramref name="promises"/> Π½Π΅ ΠΌΠΎΠΆΠ΅Ρ‚ Π±Ρ‹Ρ‚ΡŒ null</exception>
652 654 public static IPromise<T[]> CreateComposite(IList<IPromise<T>> promises) {
653 655 if (promises == null)
654 656 throw new ArgumentNullException();
655 657
656 658 // создаСм аккумулятор для Ρ€Π΅Π·ΡƒΠ»ΡŒΡ‚Π°Ρ‚ΠΎΠ² ΠΈ Ρ€Π΅Π·ΡƒΠ»ΡŒΡ‚ΠΈΡ€ΡƒΡŽΡ‰Π΅Π΅ ΠΎΠ±Π΅Ρ‰Π°Π½ΠΈΠ΅
657 659 var result = new T[promises.Count];
658 660 var promise = new Promise<T[]>();
659 661
660 662 // special case
661 663 if (promises.Count == 0) {
662 664 promise.Resolve(result);
663 665 return promise;
664 666 }
665 667
666 668 int pending = promises.Count;
667 669
668 670 for (int i = 0; i < promises.Count; i++) {
669 671 var dest = i;
670 672
671 673 if (promises[i] != null) {
672 674 promises[i].Then(
673 675 x => {
674 676 result[dest] = x;
675 677 if (Interlocked.Decrement(ref pending) == 0)
676 678 promise.Resolve(result);
677 679 },
678 680 e => {
679 681 promise.Reject(e);
680 682 return default(T);
681 683 }
682 684 );
683 685 } else {
684 686 if (Interlocked.Decrement(ref pending) == 0)
685 687 promise.Resolve(result);
686 688 }
687 689 }
688 690
689 691 promise.Cancelled(
690 692 () => {
691 693 foreach (var d in promises)
692 694 if (d != null && d.IsExclusive)
693 695 d.Cancel();
694 696 }
695 697 );
696 698
697 699 return promise;
698 700 }
699 701
700 702 /// <summary>
701 703 /// ΠžΠ±ΡŠΠ΅Π΄ΠΈΠ½ΡΠ΅Ρ‚ нСсколько ΠΎΠ±Π΅Ρ‰Π°Π½ΠΈΠΉ Π² ΠΎΠ΄Π½ΠΎ. Π Π΅Π·ΡƒΠ»ΡŒΡ‚ΠΈΡ€ΡƒΡŽΡ‰Π΅Π΅ ΠΎΠ±Π΅Ρ‰Π°Π½ΠΈΠ΅ Π±ΡƒΠ΄Π΅Ρ‚ Π²Ρ‹ΠΏΠΎΠ»Π½Π΅Π½ΠΎ ΠΏΡ€ΠΈ
702 704 /// Π²Ρ‹ΠΏΠΎΠ»Π½Π΅Π½ΠΈΠΈ всСх ΡƒΠΊΠ°Π·Π°Π½Π½Ρ‹Ρ… ΠΎΠ±Π΅Ρ‰Π°Π½ΠΈΠΉ. ΠŸΡ€ΠΈ этом Π²ΠΎΠ·Π²Ρ€Π°Ρ‰Π°Π΅ΠΌΡ‹Π΅ значСния ΠΏΠ΅Ρ€Π²ΠΈΡ‡Π½Ρ‹Ρ… ΠΎΠ±Π΅Ρ‰Π°Π½ΠΈΠΉ
703 705 /// ΠΈΠ³Π½ΠΎΡ€ΠΈΡ€ΡƒΡŽΡ‚ΡΡ.
704 706 /// </summary>
705 707 /// <param name="promises">ΠšΠΎΠ»Π»Π΅ΠΊΡ†ΠΈΡ ΠΏΠ΅Ρ€Π²ΠΈΡ‡Π½Ρ‹Ρ… ΠΎΠ±Π΅Ρ‰Π°Π½ΠΈΠΉ, ΠΊΠΎΡ‚ΠΎΡ€Ρ‹Π΅ Π±ΡƒΠ΄ΡƒΡ‚ ΠΎΠ±ΡŠΠ΅Π΄Π΅Π½Π΅Π½Ρ‹ Π² ΠΎΠ΄Π½ΠΎ.</param>
706 708 /// <returns>НовоС ΠΎΠ±Π΅Ρ‰Π°Π½ΠΈΠ΅, ΠΎΠ±ΡŠΠ΅Π΄ΠΈΠ½ΡΡŽΡ‰Π΅Π΅ Π² сСбС ΠΏΠ΅Ρ€Π΅Π΄Π°Π½Π½Ρ‹Π΅.</returns>
707 709 /// <remarks>
708 710 /// Если Π² ΠΊΠΎΠ»Π»Π΅ΠΊΡ†ΠΈΠΈ Π²ΡΡ‚Ρ€Π΅Ρ‡Π°ΡŽΡŒΡΡ <c>null</c>, Ρ‚ΠΎ ΠΎΠ½ΠΈ Π²ΠΎΡΠΏΡ€ΠΈΠ½ΠΈΠΌΠ°ΡŽΡ‚ΡΡ ΠΊΠ°ΠΊ Π²Ρ‹ΠΏΠΎΠ»Π½Π΅Π½Π½Ρ‹Π΅ обСщания.
709 711 /// </remarks>
710 712 public static IPromise CreateComposite(ICollection<IPromise> promises) {
711 713 if (promises == null)
712 714 throw new ArgumentNullException();
713 715 if (promises.Count == 0)
714 716 return Promise<object>.ResultToPromise(null);
715 717
716 718 int countdown = promises.Count;
717 719
718 720 var result = new Promise<object>();
719 721
720 722 foreach (var d in promises) {
721 723 if (d == null) {
722 724 if (Interlocked.Decrement(ref countdown) == 0)
723 725 result.Resolve(null);
724 726 } else {
725 727 d.Then(() => {
726 728 if (Interlocked.Decrement(ref countdown) == 0)
727 729 result.Resolve(null);
728 730 });
729 731 }
730 732 }
731 733
732 734 result.Cancelled(() => {
733 735 foreach (var d in promises)
734 736 if (d != null && d.IsExclusive)
735 737 d.Cancel();
736 738 });
737 739
738 740 return result;
739 741 }
740 742
741 743 public static Promise<T> ResultToPromise(T result) {
742 744 var p = new Promise<T>();
743 745 p.Resolve(result);
744 746 return p;
745 747 }
746 748
747 749 public static Promise<T> ExceptionToPromise(Exception error) {
748 750 if (error == null)
749 751 throw new ArgumentNullException();
750 752
751 753 var p = new Promise<T>();
752 754 p.Reject(error);
753 755 return p;
754 756 }
755 757
756 758 #region IPromiseBase explicit implementation
757 759
758 760 IPromise IPromise.Then(Action success, ErrorHandler error, Action cancel) {
759 761 return Then(
760 762 x => success(),
761 763 e => {
762 764 error(e);
763 765 return default(T);
764 766 },
765 767 cancel
766 768 );
767 769 }
768 770
769 771 IPromise IPromise.Then(Action success, ErrorHandler error) {
770 772 return Then(
771 773 x => success(),
772 774 e => {
773 775 error(e);
774 776 return default(T);
775 777 }
776 778 );
777 779 }
778 780
779 781 IPromise IPromise.Then(Action success) {
780 782 return Then(x => success());
781 783 }
782 784
783 785 void IPromise.Last(Action success, ErrorHandler error, Action cancel) {
784 786 Last(x => success(), error, cancel);
785 787 }
786 788
787 789 void IPromise.Last(Action success, ErrorHandler error) {
788 790 Last(x => success(), error, null);
789 791 }
790 792
791 793 void IPromise.Last(Action success) {
792 794 Last(x => success(), null, null);
793 795 }
794 796
795 797 IPromise IPromise.Error(ErrorHandler error) {
796 798 return Error(error);
797 799 }
798 800
799 801 IPromise IPromise.Anyway(Action handler) {
800 802 return Anyway(handler);
801 803 }
802 804
803 805 IPromise IPromise.Cancelled(Action handler) {
804 806 return Cancelled(handler);
805 807 }
806 808
807 809 void IPromise.Join() {
808 810 Join();
809 811 }
810 812
811 813 void IPromise.Join(int timeout) {
812 814 Join(timeout);
813 815 }
814 816
815 817 #endregion
816 818
817 819
818 820
819 821 }
820 822 }
General Comments 0
You need to be logged in to leave comments. Login now