##// END OF EJS Templates
Refactoring of the IPromise<T> interface...
cin -
r76:c761fc982e1d v2
parent child
Show More
@@ -1,87 +1,41
1 1 using System;
2 2 using System.Windows.Forms;
3 3 using System.Threading;
4 4
5 5 namespace Implab.Fx
6 6 {
7 7 public static class PromiseHelpers
8 8 {
9 9 /// <summary>
10 10 /// ΠŸΠ΅Ρ€Π΅Π½Π°ΠΏΡ€Π°Π²Π»ΡΠ΅Ρ‚ ΠΎΠ±Ρ€Π°Π±ΠΎΡ‚ΠΊΡƒ обСщания Π² ΠΏΠΎΡ‚ΠΎΠΊ ΡƒΠΊΠ°Π·Π°Π½Π½ΠΎΠ³ΠΎ элСмСнта управлСния.
11 11 /// </summary>
12 12 /// <typeparam name="T">Π’ΠΈΠΏ Ρ€Π΅Π·ΡƒΠ»ΡŒΡ‚Π°Ρ‚Π° обСщания</typeparam>
13 13 /// <param name="that">Π˜ΡΡ…ΠΎΠ΄Π½ΠΎΠ΅ ΠΎΠ±Π΅Ρ‰Π°Π½ΠΈΠ΅</param>
14 14 /// <param name="ctl">Π­Π»Π΅ΠΌΠ΅Π½Ρ‚ управлСния</param>
15 15 /// <returns>НовоС ΠΎΠ±Π΅Ρ‰Π°Π½ΠΈΠ΅, ΠΎΠ±Ρ€Π°Π±ΠΎΡ‚Ρ‡ΠΈΠΊΠΈ ΠΊΠΎΡ‚ΠΎΡ€ΠΎΠ³ΠΎ Π±ΡƒΠ΄ΡƒΡ‚ Π²Ρ‹ΠΏΠΎΠ»Π½Π΅Π½Ρ‹ Π² ΠΏΠΎΡ‚ΠΎΠΊΠ΅ элСмСнта управлСния.</returns>
16 16 /// <exception cref="ArgumentNullException">ΠŸΠ°Ρ€Π°ΠΌΠ΅Ρ‚Ρ€ Π½Π΅ ΠΌΠΎΠΆΠ΅Ρ‚ Π±Ρ‹Ρ‚ΡŒ <c>null</c>.</exception>
17 17 /// <example>
18 18 /// client
19 19 /// .Get("description.txt") // returns a promise
20 /// .DirectToControl(m_ctl) // handle the promise in the thread of the control
20 /// .DispatchToControl(m_ctl) // handle the promise in the thread of the control
21 21 /// .Then(
22 22 /// description => m_ctl.Text = description // now it's safe
23 23 /// )
24 24 /// </example>
25 public static Promise<T> DispatchToControl<T>(this Promise<T> that, Control ctl)
25 public static IPromise<T> DispatchToControl<T>(this IPromise<T> that, Control ctl)
26 26 {
27 if (that == null)
28 throw new ArgumentNullException("that");
29 if (ctl == null)
30 throw new ArgumentNullException("ctl");
27 Safe.ArgumentNotNull(that, "that");
28 Safe.ArgumentNotNull(ctl, "ctl");
31 29
32 30 var directed = new ControlBoundPromise<T>(ctl,that,true);
33 31
34 that.Then(
32 that.Last(
35 33 directed.Resolve,
36 err =>
37 {
38 directed.Reject(err);
39 return default(T);
40 }
34 directed.Reject,
35 directed.Cancel
41 36 );
42 37
43 38 return directed;
44 39 }
45
46 /// <summary>
47 /// НаправляСт ΠΎΠ±Ρ€Π°Π±ΠΎΡ‚ΠΊΡƒ обСщания Π² Ρ‚Π΅ΠΊΡƒΡ‰ΠΈΠΉ ΠΏΠΎΡ‚ΠΎΠΊ, Ссли Ρƒ Π½Π΅Π³ΠΎ сущСствуСт контСкст синхронизации.
48 /// </summary>
49 /// <typeparam name="T">Π’ΠΈΠΏ Ρ€Π΅Π·ΡƒΠ»ΡŒΡ‚Π°Ρ‚Π° обСщания.</typeparam>
50 /// <param name="that">ΠžΠ±Π΅Ρ‰Π°Π½ΠΈΠ΅ ΠΊΠΎΡ‚ΠΎΡ€ΠΎΠ΅ Π½ΡƒΠΆΠ½ΠΎ ΠΎΠ±Ρ€Π°Π±ΠΎΡ‚Π°Ρ‚ΡŒ Π² Ρ‚Π΅ΠΊΡƒΡ‰Π΅ΠΌ ΠΏΠΎΡ‚ΠΎΠΊΠ΅.</param>
51 /// <returns>ΠŸΠ΅Ρ€Π΅Π½Π°ΠΏΡ€Π°Π²Π»Π΅Π½Π½ΠΎΠ΅ ΠΎΠ±Π΅Ρ‰Π°Π½ΠΈΠ΅.</returns>
52 public static Promise<T> DispatchToCurrentThread<T>(this Promise<T> that)
53 {
54 var sync = SynchronizationContext.Current;
55 if (sync == null)
56 throw new InvalidOperationException("The current thread doesn't have a syncronization context");
57 return DispatchToSyncContext(that, sync);
58 }
59
60 /// <summary>
61 /// НаправляСт ΠΎΠ±Ρ€Π°Π±ΠΎΡ‚ΠΊΡƒ обСщания Π² ΡƒΠΊΠ°Π·Π°Π½Π½Ρ‹ΠΉ контСкст синхронизации.
62 /// </summary>
63 /// <typeparam name="T">Π’ΠΈΠΏ Ρ€Π΅Π·ΡƒΠ»ΡŒΡ‚Π°Ρ‚Π° обСщания.</typeparam>
64 /// <param name="that">ΠžΠ±Π΅Ρ‰Π°Π½ΠΈΠ΅, ΠΊΠΎΡ‚ΠΎΡ€ΠΎΠ΅ трСбуСтся ΠΎΠ±Ρ€Π°Π±ΠΎΡ‚Π°Ρ‚ΡŒ Π² ΡƒΠΊΠ°Π·Π°Π½Π½ΠΎΠΌ контСкстС синхронизации.</param>
65 /// <param name="sync">ΠšΠΎΠ½Ρ‚Π΅ΠΊΡΡ‚ синхронизации Π² ΠΊΠΎΡ‚ΠΎΡ€Ρ‹ΠΉ Π±ΡƒΠ΄Π΅Ρ‚ Π½Π°ΠΏΡ€Π°Π²Π»Π΅Π½ΠΎ ΠΎΠ±Π΅Ρ‰Π°Π½ΠΈΠ΅.</param>
66 /// <returns>НовоС ΠΎΠ±Π΅Ρ‰Π°Π½ΠΈΠ΅, ΠΊΠΎΡ‚ΠΎΡ€ΠΎΠ΅ Π±ΡƒΠ΄Π΅Ρ‚ ΠΎΠ±Ρ€Π°Π±Π°Ρ‚Ρ‹Π²Π°Ρ‚ΡŒΡΡ Π² ΡƒΠΊΠ°Π·Π°Π½Π½ΠΎΠΌ контСкстС.</returns>
67 public static Promise<T> DispatchToSyncContext<T>(this Promise<T> that, SynchronizationContext sync)
68 {
69 if (that == null)
70 throw new ArgumentNullException("that");
71 if (sync == null)
72 throw new ArgumentNullException("sync");
73
74 var d = new Promise<T>();
75
76 that.Then(
77 res => sync.Post(state => d.Resolve(res), null),
78 err => {
79 sync.Post(state => d.Reject(err), null);
80 return default(T);
81 }
82 );
83
84 return d;
85 }
86 40 }
87 41 }
@@ -1,36 +1,35
1 1 using System.Reflection;
2 2 using System.Runtime.CompilerServices;
3 3 using System.Runtime.InteropServices;
4 4
5 5 // General Information about an assembly is controlled through the following
6 6 // set of attributes. Change these attribute values to modify the information
7 7 // associated with an assembly.
8 8 [assembly: AssemblyTitle("Implab.Fx")]
9 9 [assembly: AssemblyDescription("")]
10 10 [assembly: AssemblyConfiguration("")]
11 11 [assembly: AssemblyCompany("")]
12 12 [assembly: AssemblyProduct("Implab.Fx")]
13 13 [assembly: AssemblyCopyright("Copyright Β© 2013")]
14 14 [assembly: AssemblyTrademark("")]
15 15 [assembly: AssemblyCulture("")]
16 16
17 17 // Setting ComVisible to false makes the types in this assembly not visible
18 18 // to COM components. If you need to access a type in this assembly from
19 19 // COM, set the ComVisible attribute to true on that type.
20 20 [assembly: ComVisible(false)]
21 21
22 22 // The following GUID is for the ID of the typelib if this project is exposed to COM
23 23 [assembly: Guid("d239c29f-98e2-4942-9569-554a8511d07b")]
24 24
25 25 // Version information for an assembly consists of the following four values:
26 26 //
27 27 // Major Version
28 28 // Minor Version
29 29 // Build Number
30 30 // Revision
31 31 //
32 32 // You can specify all the values or you can default the Build and Revision Numbers
33 33 // by using the '*' as shown below:
34 34 // [assembly: AssemblyVersion("1.0.*")]
35 [assembly: AssemblyVersion("1.0.0.0")]
36 [assembly: AssemblyFileVersion("1.0.0.0")]
35 [assembly: AssemblyVersion("2.0.*")]
@@ -1,392 +1,423
1 1 using System;
2 2 using Microsoft.VisualStudio.TestTools.UnitTesting;
3 3 using System.Reflection;
4 4 using System.Threading;
5 5 using Implab.Parallels;
6 6
7 7 namespace Implab.Test {
8 8 [TestClass]
9 9 public class AsyncTests {
10 10 [TestMethod]
11 11 public void ResolveTest() {
12 12 int res = -1;
13 13 var p = new Promise<int>();
14 14 p.Then(x => res = x);
15 15 p.Resolve(100);
16 16
17 17 Assert.AreEqual(100, res);
18 18 }
19 19
20 20 [TestMethod]
21 21 public void RejectTest() {
22 22 int res = -1;
23 23 Exception err = null;
24 24
25 25 var p = new Promise<int>();
26 26 p.Then(
27 27 x => res = x,
28 28 e => {
29 29 err = e;
30 30 return -2;
31 31 }
32 32 );
33 33 p.Reject(new ApplicationException("error"));
34 34
35 35 Assert.AreEqual(res, -1);
36 36 Assert.AreEqual(err.Message, "error");
37 37
38 38 }
39 39
40 40 [TestMethod]
41 public void CancelExceptionTest() {
42 var p = new Promise<bool>();
43 p.Cancel();
44
45 var p2 = p.Cancelled(() => {
46 throw new ApplicationException("CANCELLED");
47 });
48
49 try {
50 p2.Join();
51 Assert.Fail();
52 } catch (ApplicationException err) {
53 Assert.AreEqual("CANCELLED", err.InnerException.Message);
54 }
55
56 }
57
58 [TestMethod]
59 public void ContinueOnCancelTest() {
60 var p = new Promise<bool>();
61 p.Cancel();
62
63 var p2 = p
64 .Cancelled(() => {
65 throw new ApplicationException("CANCELLED");
66 })
67 .Error(e => true);
68
69 Assert.AreEqual(true, p2.Join());
70 }
71
72 [TestMethod]
41 73 public void JoinSuccessTest() {
42 74 var p = new Promise<int>();
43 75 p.Resolve(100);
44 76 Assert.AreEqual(p.Join(), 100);
45 77 }
46 78
47 79 [TestMethod]
48 80 public void JoinFailTest() {
49 81 var p = new Promise<int>();
50 82 p.Reject(new ApplicationException("failed"));
51 83
52 84 try {
53 85 p.Join();
54 86 throw new ApplicationException("WRONG!");
55 87 } catch (TargetInvocationException err) {
56 88 Assert.AreEqual(err.InnerException.Message, "failed");
57 89 } catch {
58 90 Assert.Fail("Got wrong excaption");
59 91 }
60 92 }
61 93
62 94 [TestMethod]
63 95 public void MapTest() {
64 96 var p = new Promise<int>();
65 97
66 var p2 = p.Map(x => x.ToString());
98 var p2 = p.Then(x => x.ToString());
67 99 p.Resolve(100);
68 100
69 101 Assert.AreEqual(p2.Join(), "100");
70 102 }
71 103
72 104 [TestMethod]
73 105 public void FixErrorTest() {
74 106 var p = new Promise<int>();
75 107
76 108 var p2 = p.Error(e => 101);
77 109
78 110 p.Reject(new Exception());
79 111
80 112 Assert.AreEqual(p2.Join(), 101);
81 113 }
82 114
83 115 [TestMethod]
84 116 public void ChainTest() {
85 117 var p1 = new Promise<int>();
86 118
87 119 var p3 = p1.Chain(x => {
88 120 var p2 = new Promise<string>();
89 121 p2.Resolve(x.ToString());
90 122 return p2;
91 123 });
92 124
93 125 p1.Resolve(100);
94 126
95 127 Assert.AreEqual(p3.Join(), "100");
96 128 }
97 129
98 130 [TestMethod]
99 131 public void PoolTest() {
100 132 var pid = Thread.CurrentThread.ManagedThreadId;
101 133 var p = AsyncPool.Invoke(() => Thread.CurrentThread.ManagedThreadId);
102 134
103 135 Assert.AreNotEqual(pid, p.Join());
104 136 }
105 137
106 138 [TestMethod]
107 139 public void WorkerPoolSizeTest() {
108 140 var pool = new WorkerPool(5, 10, 0);
109 141
110 142 Assert.AreEqual(5, pool.PoolSize);
111 143
112 144 pool.Invoke(() => { Thread.Sleep(100000000); return 10; });
113 145 pool.Invoke(() => { Thread.Sleep(100000000); return 10; });
114 146 pool.Invoke(() => { Thread.Sleep(100000000); return 10; });
115 147
116 148 Assert.AreEqual(5, pool.PoolSize);
117 149
118 150 for (int i = 0; i < 100; i++)
119 151 pool.Invoke(() => { Thread.Sleep(100000000); return 10; });
120 152 Thread.Sleep(200);
121 153 Assert.AreEqual(10, pool.PoolSize);
122 154
123 155 pool.Dispose();
124 156 }
125 157
126 158 [TestMethod]
127 159 public void WorkerPoolCorrectTest() {
128 160 var pool = new WorkerPool(0,1000,100);
129 161
130 162 int iterations = 1000;
131 163 int pending = iterations;
132 164 var stop = new ManualResetEvent(false);
133 165
134 166 var count = 0;
135 167 for (int i = 0; i < iterations; i++) {
136 168 pool
137 169 .Invoke(() => 1)
138 170 .Then(x => Interlocked.Add(ref count, x))
139 171 .Then(x => Math.Log10(x))
140 172 .Anyway(() => {
141 173 Interlocked.Decrement(ref pending);
142 174 if (pending == 0)
143 175 stop.Set();
144 176 });
145 177 }
146 178
147 179 stop.WaitOne();
148 180
149 181 Assert.AreEqual(iterations, count);
150 182 Console.WriteLine("Max threads: {0}", pool.MaxRunningThreads);
151 183 pool.Dispose();
152 184
153 185 }
154 186
155 187 [TestMethod]
156 188 public void WorkerPoolDisposeTest() {
157 189 var pool = new WorkerPool(5, 20);
158 190 Assert.AreEqual(5, pool.PoolSize);
159 191 pool.Dispose();
160 192 Thread.Sleep(500);
161 193 Assert.AreEqual(0, pool.PoolSize);
162 194 pool.Dispose();
163 195 }
164 196
165 197 [TestMethod]
166 198 public void MTQueueTest() {
167 199 var queue = new MTQueue<int>();
168 200 int res;
169 201
170 202 queue.Enqueue(10);
171 203 Assert.IsTrue(queue.TryDequeue(out res));
172 204 Assert.AreEqual(10, res);
173 205 Assert.IsFalse(queue.TryDequeue(out res));
174 206
175 207 for (int i = 0; i < 1000; i++)
176 208 queue.Enqueue(i);
177 209
178 210 for (int i = 0; i < 1000; i++) {
179 211 queue.TryDequeue(out res);
180 212 Assert.AreEqual(i, res);
181 213 }
182 214
183 215 int writers = 0;
184 216 int readers = 0;
185 217 var stop = new ManualResetEvent(false);
186 218 int total = 0;
187 219
188 int itemsPerWriter = 1000;
189 int writersCount = 3;
220 int itemsPerWriter = 10000;
221 int writersCount = 10;
190 222
191 223 for (int i = 0; i < writersCount; i++) {
192 224 Interlocked.Increment(ref writers);
193 225 var wn = i;
194 226 AsyncPool
195 227 .InvokeNewThread(() => {
196 228 for (int ii = 0; ii < itemsPerWriter; ii++) {
197 229 queue.Enqueue(1);
198 230 }
199 231 return 1;
200 232 })
201 233 .Anyway(() => Interlocked.Decrement(ref writers));
202 234 }
203 235
204 236 for (int i = 0; i < 10; i++) {
205 237 Interlocked.Increment(ref readers);
206 238 var wn = i;
207 239 AsyncPool
208 240 .InvokeNewThread(() => {
209 241 int t;
210 242 do {
211 243 while (queue.TryDequeue(out t))
212 244 Interlocked.Add(ref total, t);
213 245 } while (writers > 0);
214 246 return 1;
215 247 })
216 248 .Anyway(() => {
217 249 Interlocked.Decrement(ref readers);
218 250 if (readers == 0)
219 251 stop.Set();
220 252 });
221 253 }
222 254
223 255 stop.WaitOne();
224 256
225 257 Assert.AreEqual(itemsPerWriter * writersCount, total);
226 258 }
227 259
228 260 [TestMethod]
229 261 public void ParallelMapTest() {
230 262
231 263 int count = 100000;
232 264
233 265 double[] args = new double[count];
234 266 var rand = new Random();
235 267
236 268 for (int i = 0; i < count; i++)
237 269 args[i] = rand.NextDouble();
238 270
239 271 var t = Environment.TickCount;
240 272 var res = args.ParallelMap(x => Math.Sin(x*x), 4).Join();
241 273
242 274 Console.WriteLine("Map complete in {0} ms", Environment.TickCount - t);
243 275
244 276 t = Environment.TickCount;
245 277 for (int i = 0; i < count; i++)
246 278 Assert.AreEqual(Math.Sin(args[i] * args[i]), res[i]);
247 279 Console.WriteLine("Verified in {0} ms", Environment.TickCount - t);
248 280 }
249 281
250 282 [TestMethod]
251 283 public void ChainedMapTest() {
252 284
253 285 using (var pool = new WorkerPool(0,100,100)) {
254 286 int count = 10000;
255 287
256 288 double[] args = new double[count];
257 289 var rand = new Random();
258 290
259 291 for (int i = 0; i < count; i++)
260 292 args[i] = rand.NextDouble();
261 293
262 294 var t = Environment.TickCount;
263 295 var res = args
264 296 .ChainedMap(
265 297 x => pool.Invoke(
266 298 () => Math.Sin(x * x)
267 299 ),
268 300 4
269 301 )
270 302 .Join();
271 303
272 304 Console.WriteLine("Map complete in {0} ms", Environment.TickCount - t);
273 305
274 306 t = Environment.TickCount;
275 307 for (int i = 0; i < count; i++)
276 308 Assert.AreEqual(Math.Sin(args[i] * args[i]), res[i]);
277 309 Console.WriteLine("Verified in {0} ms", Environment.TickCount - t);
278 310 Console.WriteLine("Max workers: {0}", pool.MaxRunningThreads);
279 311 }
280 312 }
281 313
282 314 [TestMethod]
283 315 public void ParallelForEachTest() {
284 316
285 317 int count = 100000;
286 318
287 319 int[] args = new int[count];
288 320 var rand = new Random();
289 321
290 322 for (int i = 0; i < count; i++)
291 323 args[i] = (int)(rand.NextDouble() * 100);
292 324
293 325 int result = 0;
294 326
295 327 var t = Environment.TickCount;
296 328 args.ParallelForEach(x => Interlocked.Add(ref result, x), 4).Join();
297 329
298 330 Console.WriteLine("Iteration complete in {0} ms, result: {1}", Environment.TickCount - t, result);
299 331
300 332 int result2 = 0;
301 333
302 334 t = Environment.TickCount;
303 335 for (int i = 0; i < count; i++)
304 336 result2 += args[i];
305 337 Assert.AreEqual(result2, result);
306 338 Console.WriteLine("Verified in {0} ms", Environment.TickCount - t);
307 339 }
308 340
309 341 [TestMethod]
310 342 public void ComplexCase1Test() {
311 343 var flags = new bool[3];
312 344
313 345 // op1 (aync 200ms) => op2 (async 200ms) => op3 (sync map)
314 346
315 347 var p = PromiseHelper
316 348 .Sleep(200, "Alan")
317 349 .Cancelled(() => flags[0] = true)
318 350 .Chain(x =>
319 351 PromiseHelper
320 352 .Sleep(200, "Hi, " + x)
321 .Map(y => y)
353 .Then(y => y)
322 354 .Cancelled(() => flags[1] = true)
323 355 )
324 356 .Cancelled(() => flags[2] = true);
325 357 Thread.Sleep(300);
326 358 p.Cancel();
327 359 try {
328 360 Assert.AreEqual(p.Join(), "Hi, Alan");
329 361 Assert.Fail("Shouldn't get here");
330 362 } catch (OperationCanceledException) {
331 363 }
332 364
333 365 Assert.IsFalse(flags[0]);
334 366 Assert.IsTrue(flags[1]);
335 367 Assert.IsTrue(flags[2]);
336 368 }
337 369
338 370 [TestMethod]
339 371 public void ChainedCancel1Test() {
340 372 // ΠΏΡ€ΠΈ ΠΎΡ‚ΠΌΠ΅Π½Π΅ сцСплСнной асинхронной ΠΎΠΏΠ΅Ρ€Π°Ρ†ΠΈΠΈ всС ΠΎΠ±Π΅Ρ‰Π°Π½ΠΈΠ΅ Π΄ΠΎΠ»ΠΆΠ½ΠΎ
341 373 // Π·Π°Π²Π΅Ρ€ΡˆΠ°Ρ‚ΡŒΡΡ ошибкой OperationCanceledException
342 374 var p = PromiseHelper
343 375 .Sleep(1, "Hi, HAL!")
344 .Chain(x => {
376 .Then(x => {
345 377 // запускаСм Π΄Π²Π΅ асинхронныС ΠΎΠΏΠ΅Ρ€Π°Ρ†ΠΈΠΈ
346 378 var result = PromiseHelper.Sleep(1000, "HEM ENABLED!!!");
347 379 // вторая опСрация отмСняСт ΠΏΠ΅Ρ€Π²ΡƒΡŽ Π΄ΠΎ Π·Π°Π²Π΅Ρ€ΡˆΠ΅Π½ΠΈΡ
348 380 PromiseHelper
349 381 .Sleep(100, "HAL, STOP!")
350 382 .Then(() => result.Cancel());
351 383 return result;
352 384 });
353 385 try {
354 386 p.Join();
355 387 } catch (TargetInvocationException err) {
356 388 Assert.IsTrue(err.InnerException is OperationCanceledException);
357 389 }
358 390 }
359 391
360 392 [TestMethod]
361 393 public void ChainedCancel2Test() {
362 394 // ΠΏΡ€ΠΈ ΠΎΡ‚ΠΌΠ΅Π½Π΅ Ρ†Π΅ΠΏΠΎΡ‡ΠΊΠΈ ΠΎΠ±Π΅Ρ‰Π°Π½ΠΈΠΉ, Π²Π»ΠΎΠΆΠ΅Π½Π½Ρ‹Π΅ ΠΎΠΏΠ΅Ρ€Π°Ρ†ΠΈΠΈ Ρ‚Π°ΠΊΠΆΠ΅ Π΄ΠΎΠ»ΠΆΠ½Ρ‹ ΠΎΡ‚ΠΌΠ΅Π½ΡΡ‚ΡŒΡΡ
363 IPromise p = null;
364 395 var pSurvive = new Promise<bool>();
365 396 var hemStarted = new ManualResetEvent(false);
366 p = PromiseHelper
397 var p = PromiseHelper
367 398 .Sleep(1, "Hi, HAL!")
368 399 .Chain(x => {
369 400 hemStarted.Set();
370 401 // запускаСм Π΄Π²Π΅ асинхронныС ΠΎΠΏΠ΅Ρ€Π°Ρ†ΠΈΠΈ
371 402 var result = PromiseHelper
372 .Sleep(1000, "HEM ENABLED!!!")
403 .Sleep(10000, "HEM ENABLED!!!")
373 404 .Then(s => pSurvive.Resolve(false));
374 405
375 406 result
376 407 .Cancelled(() => pSurvive.Resolve(true));
377 408
378 409 return result;
379 410 });
380 411
381 412 hemStarted.WaitOne();
382 413 p.Cancel();
383 414
384 415 try {
385 416 p.Join();
386 417 } catch (OperationCanceledException) {
387 418 Assert.IsTrue(pSurvive.Join());
388 419 }
389 420 }
390 421 }
391 422 }
392 423
@@ -1,238 +1,238
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.Threading.Tasks;
7 7
8 8 namespace Implab.Diagnostics {
9 9 /// <summary>
10 10 /// ΠšΠΎΠ½Ρ‚Π΅ΠΊΡΡ‚ трассировки, привязываСтся ΠΊ ΠΏΠΎΡ‚ΠΎΠΊΡƒ ΠΈ содСрТит Π² сСбС ΠΈΠ½Ρ„ΠΎΡ€ΠΌΠ°Ρ†ΠΈΡŽ ΠΎ стСкС логичСских ΠΎΠΏΠ΅Ρ€Π°Ρ†ΠΈΠΉ.
11 11 /// </summary>
12 12 /// <remarks>
13 13 /// ΠšΠΎΠ½Ρ‚Π΅ΠΊΡΡ‚ трассировки пСрСдаСтся ΡΠ»ΡƒΡˆΠ°Ρ‚Π΅Π»ΡΠΌ событий для опрСдСлСния мСста, Π³Π΄Π΅ Π²ΠΎΠ·Π½ΠΈΠΊΠ»ΠΎ событиС.
14 14 /// </remarks>
15 15 public class TraceContext {
16 16 LogicalOperation m_currentOperation;
17 17 readonly LogicalOperation m_bound;
18 18 readonly int m_threadId;
19 19
20 20 [ThreadStatic]
21 21 static TraceContext _current;
22 22
23 23 /// <summary>
24 24 /// Π’Π΅ΠΊΡƒΡ‰ΠΈΠΉ контСкст трассировки для ΠΏΠΎΡ‚ΠΎΠΊΠ°, создаСтся астоматичСски ΠΏΡ€ΠΈ ΠΏΠ΅Ρ€Π²ΠΎΠΌ ΠΎΠ±Ρ€Π°Ρ‰Π΅Π½ΠΈΠΈ.
25 25 /// </summary>
26 26 public static TraceContext Current {
27 27 get {
28 28 if (_current == null) {
29 29 _current = new TraceContext();
30 30 _current.LogEvent(TraceEventType.Created,"[{0}]", _current.ThreadId);
31 31 }
32 32 return _current;
33 33 }
34 34 }
35 35
36 36 TraceContext(TraceContext context)
37 37 : this(context, false) {
38 38 }
39 39
40 40 TraceContext(TraceContext context, bool attach) {
41 41 if (context == null)
42 42 throw new ArgumentNullException("context");
43 43
44 44 m_currentOperation = context.CurrentOperation;
45 45 m_bound = attach ? context.BoundOperation : context.CurrentOperation;
46 46 m_threadId = Thread.CurrentThread.ManagedThreadId;
47 47 }
48 48
49 49 TraceContext() {
50 50 m_currentOperation = new LogicalOperation();
51 51 m_bound = m_currentOperation;
52 52 m_threadId = Thread.CurrentThread.ManagedThreadId;
53 53 }
54 54
55 55 /// <summary>
56 56 /// ΠŸΡ€ΠΈ нСобходимости ΠΊΠΎΠΏΠΈΡ€ΡƒΠ΅Ρ‚ состояниС контСкста трассивровки Π² Ρ‚Π΅ΠΊΡƒΡ‰ΠΈΠΉ ΠΏΠΎΡ‚ΠΎΠΊ.
57 57 /// </summary>
58 58 /// <param name="from">Π˜ΡΡ…ΠΎΠ΄Π½Ρ‹ΠΉ контСкст трассировки, ΠΊΠΎΡ‚ΠΎΡ€Ρ‹ΠΉ пСрСдаСтся.</param>
59 59 /// <remarks>
60 60 /// <para>
61 61 /// ΠšΠΎΠΏΠΈΡ€ΠΎΠ²Π°Π½ΠΈΠ΅ происходит Π·Π° счСт создания Π½ΠΎΠ²ΠΎΠ³ΠΎ контСкста трассировки ΠΈ Π·Π°ΠΏΠΎΠ»Π½Π΅Π½ΠΈΠ΅ΠΌ Π΅Π³ΠΎ
62 62 /// состояния ΠΈΠ· ΠΏΠ΅Ρ€Π΅Π΄Π°Π½Π½ΠΎΠ³ΠΎ контСкста. ΠŸΡ€ΠΈ этом копируСтся стСк ΠΎΠΏΠ΅Ρ€Π°Ρ†ΠΈΠΉ, ΠΎΠ΄Π½Π°ΠΊΠΎ Π² Π½ΠΎΠ²ΠΎΠΌ
63 63 /// контСкстС Ρ€Π°Π½Π΅Π΅ Π½Π°Ρ‡Π°Ρ‚Ρ‹Π΅ логичСскиС ΠΎΠΏΠ΅Ρ€Π°Ρ†ΠΈΠΈ Π½Π΅ ΠΌΠΎΠ³ΡƒΡ‚ Π±Ρ‹Ρ‚ΡŒ Π·Π°Π²Π΅Ρ€ΡˆΠ΅Π½Ρ‹.
64 64 /// </para>
65 65 /// <para>
66 66 /// Если ΠΏΠ΅Ρ€Π΅Π΄Π°Ρ‡Π° состояния ΡΠΎΡΡ‚ΠΎΡΠ»Π°ΡΡŒ, Ρ‚ΠΎ вызываСтся событиС трассировки <see cref="TraceEventType.Fork"/>.
67 67 /// </para>
68 68 /// </remarks>
69 69 public static void Fork(TraceContext from) {
70 70 if (_current == from)
71 71 return;
72 72 if (from != null) {
73 73 var context = new TraceContext(from);
74 74 context.LogEvent(TraceEventType.Fork, "[{0}]-->[{1}]",from.ThreadId, context.ThreadId);
75 75 _current = context;
76 76 } else {
77 77 _current = new TraceContext();
78 78 }
79 79 }
80 80
81 81 /// <summary>
82 82 /// Π—Π°Π΄Π°Π΅Ρ‚ Ρ‚Π΅ΠΊΡƒΡ‰Π΅ΠΌΡƒ ΠΏΠΎΡ‚ΠΎΠΊΡƒ ΡƒΠΊΠ°Π·Π°Π½Π½Ρ‹ΠΉ контСкст, Ρ‚Π΅ΠΊΡƒΡ‰Π΅ΠΉ ΠΏΠΎΡ‚ΠΎΠΊ ΠΌΠΎΠΆΠ΅Ρ‚ Π·Π°ΠΊΠ°Π½Ρ‡ΠΈΠ²Π°Ρ‚ΡŒ Ρ€Π°Π½Π΅Π΅ Π½Π°Ρ‡Π°Ρ‚Ρ‹Π΅
83 83 /// логичСскиС ΠΎΠΏΠ΅Ρ€Π°Ρ†ΠΈΠΈ Π² ΡƒΠΊΠ°Π·Π°Π½Π½ΠΎΠΌ контСкстС.
84 84 /// </summary>
85 85 /// <param name="source"></param>
86 86 public static void Attach(TraceContext source) {
87 87 if (_current == source)
88 88 return;
89 89 if (source != null) {
90 90 var context = new TraceContext(source, true);
91 91 context.LogEvent(TraceEventType.Attach, "[{0}]-->[{1}]", source.ThreadId, context.ThreadId);
92 92 _current = context;
93 93 } else {
94 94 _current = new TraceContext();
95 95 }
96 96 }
97 97
98 98 /// <summary>
99 99 /// ΠžΡ‚ΡΠΎΠ΅Π΄ΠΈΠ½ΡΠ΅Ρ‚ Ρ‚Π΅ΠΊΡƒΡ‰ΠΈΠΉ контСкст трассировки ΠΎΡ‚ ΠΏΠΎΡ‚ΠΎΠΊΠ°, для дальнСйшСй Π΅Π³ΠΎ ΠΏΠ΅Ρ€Π΅Π΄Π°Ρ‡ΠΈ Π΄Ρ€ΡƒΠ³ΠΎΠΌΡƒ ΠΏΠΎΡ‚ΠΎΠΊΡƒ
100 100 /// <see cref="Attach(TraceContext)"/>.
101 101 /// </summary>
102 102 /// <returns>ΠšΠΎΠ½Ρ‚Π΅ΠΊΡΡ‚ трассировки ΠΏΠΎΡ‚ΠΎΠΊΠ°</returns>
103 103 /// <remarks>
104 104 /// ПослС отсоСдинСния контСкста трассировки ΠΎΡ‚ ΠΏΠΎΡ‚ΠΎΠΊΠ°, ΠΏΡ€ΠΈ ΠΏΠ΅Ρ€Π²ΠΎΠΌ ΠΎΠ±Ρ€Π°Ρ‰Π΅Π½ΠΈΠΈ ΠΊ трассировкС Π² этом
105 105 /// ΠΏΠΎΡ‚ΠΎΠΊΠ΅ Π±ΡƒΠ΄Π΅Ρ‚ создан Π½ΠΎΠ²Ρ‹ΠΉ контСкст.
106 106 /// </remarks>
107 107 public static TraceContext Detach() {
108 108 var context = Current;
109 109 context.LogEvent(TraceEventType.Detach, null);
110 110 _current = null;
111 111 return context;
112 112 }
113 113
114 114 /// <summary>
115 115 /// Π‘ΠΎΠ·Π΄Π°Π΅Ρ‚ ΠΏΠΎΡΡ‚ΠΎΡΠ½Π½ΡƒΡŽ копию Ρ‚Π΅ΠΊΡƒΡ‰Π΅Π³ΠΎ контСкста, Π΄Π°Π½Π½ΡƒΡŽ копию ΠΌΠΎΠΆΠ½ΠΎ Ρ…Ρ€Π°Π½ΠΈΡ‚ΡŒ ΠΈ ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚ΡŒ для ΠΏΠ΅Ρ€Π΅Π΄Π°Ρ‡ΠΈ Ρ‡Π΅Ρ€Π΅Π· <see cref="Fork(TraceContext)"/>
116 116 /// </summary>
117 117 /// <returns>Копия Ρ‚Π΅ΠΊΡƒΡ‰Π΅Π³ΠΎ контСкста трассировки.</returns>
118 118 public static TraceContext Snapshot() {
119 119 return _current == null ? new TraceContext() : new TraceContext(_current,false);
120 120 }
121 121
122 122 /// <summary>
123 123 /// ВыполняСт ΠΏΠ΅Ρ€Π΅Π΄Π°Π½Π½ΠΎΠ΅ дСйствиС Π² ΡƒΠΊΠ°Π·Π°Π½Π½ΠΎΠΌ контСкстС трассировки, ΠΏΠΎ ΠΎΠΊΠΎΠ½Ρ‡Π°Π½ΠΈΠΈ восстанавливаСт ΠΏΡ€Π΅Π΄Ρ‹Π΄ΡƒΡ‰ΠΈΠΉ контСкст трассировки ΠΏΠΎΡ‚ΠΎΠΊΠ°.
124 124 /// </summary>
125 125 /// <param name="action"></param>
126 126 public void Invoke(Action action) {
127 127 if (action == null)
128 128 throw new ArgumentNullException("action");
129 129 var old = _current;
130 130 Fork(this);
131 131 try {
132 132 action();
133 133 } finally {
134 134 if(_current != null)
135 135 _current.EndAllOperations();
136 136 _current = old;
137 137 }
138 138 }
139 139
140 140 /// <summary>
141 141 /// ВСкущая логичСская опСрация.
142 142 /// </summary>
143 143 public LogicalOperation CurrentOperation {
144 144 get {
145 145 return m_currentOperation;
146 146 }
147 147 }
148 148
149 149 /// <summary>
150 150 /// ΠžΠΏΠ΅Ρ€Π°Ρ†ΠΈΡ Π½ΠΈΠΆΠ΅ ΠΊΠΎΡ‚ΠΎΡ€ΠΎΠΉ нСльзя ΠΎΠΏΡƒΡΠΊΠ°Ρ‚ΡŒΡΡ Π² стСкС логичСских ΠΎΠΏΠ΅Ρ€Π°Ρ†ΠΈΠΉ, Ρ‚.Π΅. ΠΎΠ½Π° Π½Π΅ ΠΌΠΎΠΆΠ΅Ρ‚ Π±Ρ‹Ρ‚ΡŒ Π·Π°Π²Π΅Ρ€ΡˆΠ΅Π½Π° Π² Ρ‚Π΅ΠΊΡƒΡ‰Π΅ΠΌ контСкстС.
151 151 /// </summary>
152 152 public LogicalOperation BoundOperation {
153 153 get {
154 154 return m_bound;
155 155 }
156 156 }
157 157
158 158 /// <summary>
159 159 /// ΠŸΠΎΡ‚ΠΎΠΊ, Π² ΠΊΠΎΡ‚ΠΎΡ€ΠΎΠΌ создан контСкст трассировки.
160 160 /// </summary>
161 161 public int ThreadId {
162 162 get {
163 163 return m_threadId;
164 164 }
165 165 }
166 166
167 167 /// <summary>
168 168 /// НачинаСт Π±Π΅Π·Ρ‹ΠΌΡΠ½Π½ΡƒΡŽ Π»ΠΎΠ³ΠΈΡ‡Π΅ΡΠΊΡƒΡŽ ΠΎΠΏΠ΅Ρ€Π°Ρ†ΠΈΡŽ.
169 169 /// </summary>
170 170 public void StartLogicalOperation() {
171 171 StartLogicalOperation(null);
172 172 }
173 173
174 174 /// <summary>
175 175 /// НачинаСт Π»ΠΎΠ³ΠΈΡ‡Π΅ΡΠΊΡƒΡŽ ΠΎΠΏΠ΅Ρ€Π°Ρ†ΠΈΡŽ с ΡƒΠΊΠ°Π·Π°Π½Π½Ρ‹ΠΌ ΠΈΠΌΠ΅Π½Π΅ΠΌ. Бозданная опСрация Π±ΡƒΠ΄Π΅Ρ‚ Π΄ΠΎΠ±Π²Π°Π»Π΅Π½Π° Π² стСк логичСских ΠΎΠΏΠ΅Ρ€Π°Ρ†ΠΈΠΉ контСкста, Π·Π°Ρ‚Π΅ΠΌ Π±ΡƒΠ΄Π΅Ρ‚ создано ΡΠΎΠΎΡ‚Π²Π΅Ρ‚ΡΠ²ΡƒΡŽΡ‰Π΅Π΅ событиС.
176 176 /// </summary>
177 177 /// <param name="name">Имя Π½Π°Ρ‡ΠΈΠ½Π°Π΅ΠΌΠΎΠΉ ΠΎΠΏΠ΅Ρ€Π°Ρ†ΠΈΠΈ.</param>
178 178 public void StartLogicalOperation(string name) {
179 179 m_currentOperation = new LogicalOperation(name, m_currentOperation);
180 180 LogEvent(TraceEventType.OperationStarted, name);
181 181 }
182 182
183 183 /// <summary>
184 184 /// Π—Π°ΠΊΠ°Π½Ρ‡ΠΈΠ²Π°Π΅Ρ‚ Π»ΠΎΠ³ΠΈΡ‡Π΅ΡΠΊΡƒΡŽ ΠΎΠΏΠ΅Ρ€Π°Ρ†ΠΈΡŽ Π½Π°Ρ‡Π°Ρ‚ΡƒΡŽ Π² Ρ‚Π΅ΠΊΡƒΡ‰Π΅ΠΌ контСкстС. ΠžΠΏΠ΅Ρ€Π°Ρ†ΠΈΠΈ, Π½Π°Ρ‡Π°Ρ‚Ρ‹Π΅ Π² Π΄Ρ€ΡƒΠ³ΠΈΡ… контСкстах Π½Π΅ ΠΌΠΎΠ³ΡƒΡ‚ Π±Ρ‹Ρ‚ΡŒ Π·Π°ΠΊΠΎΠ½Ρ‡Π΅Π½Ρ‹ Π² Ρ‚Π΅ΠΊΡƒΡ‰Π΅ΠΌ контСкстС.
185 185 /// </summary>
186 186 /// <remarks>
187 187 /// ΠŸΡ€ΠΈ Π²Ρ‹Π·ΠΎΠ²Π΅ Π΄Π°Π½Π½ΠΎΠ³ΠΎ ΠΌΠ΅Ρ‚ΠΎΠ΄Π° создаСтся событиС ΠΆΡƒΡ€Π½Π°Π»Π° трассировки, Π»ΠΈΠ±ΠΎ ΠΎ Π·Π°Π²Π΅Ρ€ΡˆΠ΅Π½ΠΈΠΈ ΠΎΠΏΠ΅Ρ€Π°Ρ†ΠΈΠΈ, Π»ΠΈΠ±ΠΎ ΠΎΠ± ошибки, ΠΏΠΎΡΠΊΠΎΠ»ΡŒΠΊΡƒ данная опСрация
188 188 /// Π½Π°Ρ‡Π°Ρ‚Π° Π² Π΄Ρ€ΡƒΠ³ΠΎΠΌ контСкстС.
189 189 /// </remarks>
190 190 public void EndLogicalOperation() {
191 191 if (m_bound == m_currentOperation) {
192 192 LogEvent(TraceEventType.Error, "Trying to end the operation which isn't belongs to current trace");
193 193 } else {
194 194 var op = m_currentOperation;
195 195 LogEvent(TraceEventType.OperationCompleted, "{0} {1} ms", op.Name, op.Duration);
196 196 m_currentOperation = m_currentOperation.Parent;
197 197 }
198 198 }
199 199
200 200 /// <summary>
201 201 /// Π‘ΠΎΠ·Π΄Π°Π΅Ρ‚ копию контСкста ΠΈ возвращаСтся Π½Π° ΠΏΡ€Π΅Π΄Ρ‹Π΄ΡƒΡ‰ΡƒΡŽ ΠΎΠΏΠ΅Ρ€Π°Ρ†ΠΈΡŽ Π² Ρ‚Π΅ΠΊΡƒΡ‰Π΅ΠΌ контСкстС, это позволяСт Π½Π°Ρ‡Π°Ρ‚ΡŒ ΠΎΠΏΠ΅Ρ€Π°Ρ†ΠΈΡŽ Π² ΠΎΠ΄Π½ΠΎΠΌ ΠΏΠΎΡ‚ΠΎΠΊΠ΅, Π° Π·Π°Π²Π΅Ρ€ΡˆΠΈΡ‚ΡŒ - Π² Π΄Ρ€ΡƒΠ³ΠΎΠΌ.
202 202 /// </summary>
203 203 /// <returns>ΠšΠΎΠ½Ρ‚Π΅ΠΊΡΡ‚ трассировки, ΠΊΠΎΡ‚ΠΎΡ€Ρ‹ΠΉ ΠΌΠΎΠΆΠ½ΠΎ ΠΏΡ€ΠΈΡΠΎΠ΅Π΄ΠΈΠ½ΠΈΡ‚ΡŒ ΠΊ Π΄Ρ€ΡƒΠ³ΠΎΠΌΡƒ ΠΏΠΎΡ‚ΠΎΠΊΡƒ.</returns>
204 204 public TraceContext DetachLogicalOperation() {
205 205 if (m_bound == m_currentOperation) {
206 206 return new TraceContext();
207 207 } else {
208 208 var detached = new TraceContext(this, true);
209 209 m_currentOperation = m_currentOperation.Parent;
210 210 return detached;
211 211 }
212 212 }
213 213
214 214 public void BindLogicalOperationToPromise(IPromise promise) {
215 215 Safe.ArgumentNotNull(promise, "promise");
216 216
217 217 var ctx = DetachLogicalOperation();
218 promise.Finally(() => {
218 promise.Anyway(() => {
219 219 var old = _current;
220 220 TraceContext.Attach(ctx);
221 221 TraceContext.Current.EndLogicalOperation();
222 222 _current = old;
223 223 });
224 224 }
225 225
226 226 /// <summary>
227 227 /// Π—Π°Π²Ρ€Π΅ΡˆΠ°Π΅Ρ‚ всС Π½Π°Ρ‡Π°Ρ‚Ρ‹Π΅ Π² этом контСкстС ΠΎΠΏΠ΅Ρ€Π°Ρ†ΠΈΠΈ
228 228 /// </summary>
229 229 public void EndAllOperations() {
230 230 while (m_bound != m_currentOperation)
231 231 EndLogicalOperation();
232 232 }
233 233
234 234 void LogEvent(TraceEventType type, string format, params object[] args) {
235 235 LogChannel<TraceEvent>.Default.LogEvent(this, TraceEvent.Create(type, format, args));
236 236 }
237 237 }
238 238 }
@@ -1,10 +1,10
1 1 using System;
2 2 using System.Collections.Generic;
3 3 using System.Linq;
4 4 using System.Text;
5 5
6 6 namespace Implab {
7 7 public interface ICancellable {
8 bool Cancel();
8 void Cancel();
9 9 }
10 10 }
@@ -1,82 +1,82
1 1 using System;
2 2 using System.Collections.Generic;
3 3 using System.Linq;
4 4 using System.Text;
5 5
6 6 namespace Implab {
7 7 public interface IPromise: ICancellable {
8 8 /// <summary>
9 9 /// Check whereather the promise has no more than one dependent promise.
10 10 /// </summary>
11 11 bool IsExclusive {
12 12 get;
13 13 }
14 14
15 15 /// <summary>
16 16 /// Π’ΠΈΠΏ Ρ€Π΅Π·ΡƒΠ»ΡŒΡ‚Π°Ρ‚Π°, ΠΏΠΎΠ»ΡƒΡ‡Π°Π΅ΠΌΠΎΠ³ΠΎ Ρ‡Π΅Ρ€Π΅Π· Π΄Π°Π½Π½ΠΎΠ΅ ΠΎΠ±Π΅Ρ‰Π°Π½ΠΈΠ΅.
17 17 /// </summary>
18 18 Type PromiseType { get; }
19 19
20 20 /// <summary>
21 21 /// ΠžΠ±Π΅Ρ‰Π°Π½ΠΈΠ΅ являСтся Π²Ρ‹ΠΏΠΎΠ»Π½Π΅Π½Ρ‹ΠΌ, Π»ΠΈΠ±ΠΎ ΡƒΡΠΏΠ΅ΡˆΠ½ΠΎ, Π»ΠΈΠ±ΠΎ с ошибкой.
22 22 /// </summary>
23 23 bool IsResolved { get; }
24 24
25 25 /// <summary>
26 26 /// ΠžΠ±Π΅Ρ‰Π°Π½ΠΈΠ΅ Π±Ρ‹Π»ΠΎ ΠΎΡ‚ΠΌΠ΅Π½Π΅Π½ΠΎ.
27 27 /// </summary>
28 28 bool IsCancelled { get; }
29 29
30 30 IPromise Then(Action success, ErrorHandler error, Action cancel);
31 31 IPromise Then(Action success, ErrorHandler error);
32 32 IPromise Then(Action success);
33 33
34 34 /// <summary>
35 35 /// ДобавляСт послСднй ΠΎΠ±Ρ€Π°Π±ΠΎΡ‚Ρ‡ΠΈΠΊ Π² Ρ†Π΅ΠΏΠΎΡ‡ΠΊΡƒ ΠΎΠ±Π΅Ρ‰Π°Π½ΠΈΠΉ, Π½Π΅ создаСт ΠΏΡ€ΠΎΠΌΠ΅ΠΆΡƒΡ‚ΠΎΡ‡Π½Ρ‹Ρ… ΠΎΠ±Π΅Ρ‰Π°Π½ΠΈΠΉ.
36 36 /// </summary>
37 37 /// <param name="success">Success.</param>
38 38 /// <param name="error">Error.</param>
39 39 /// <param name="cancel">Cancel.</param>
40 40 void Last(Action success, ErrorHandler error, Action cancel);
41 41 void Last(Action success, ErrorHandler error);
42 42 void Last(Action success);
43 43
44 44 IPromise Error(ErrorHandler error);
45 45 /// <summary>
46 46 /// ΠžΠ±Ρ€Π°Π±Π°Ρ‚Ρ‹Π²Π°Π΅Ρ‚ Π»ΠΈΠ±ΠΎ ΠΎΡˆΠΈΠ±ΠΊΡƒ, Π»ΠΈΠ±ΠΎ Ρ€Π΅Π·ΡƒΠ»ΡŒΡ‚Π°Ρ‚. Π‘ΠΎΠ±Ρ‹Ρ‚ΠΈΠ΅ ΠΎΡ‚ΠΌΠ΅Π½Ρ‹ Π½Π΅ обрабатываСтся.
47 47 /// </summary>
48 48 /// <param name="handler">ΠžΠ±Ρ€Π°Π±ΠΎΡ‚Ρ‡ΠΈΠΊ.</param>
49 49 /// <remarks>ПослС ΠΎΠ±Ρ€Π°Π±ΠΎΡ‚ΠΊΠ΅ ошибки, ΠΎΠ½Π° пСрСдаСтся дальшС.</remarks>
50 50 /// <summary>
51 51 /// ΠžΠ±Ρ€Π°Π±Π°Ρ‚Ρ‹Π²Π°Π΅Ρ‚ Π»ΠΈΠ±ΠΎ ΠΎΡˆΠΈΠ±ΠΊΡƒ, Π»ΠΈΠ±ΠΎ Ρ€Π΅Π·ΡƒΠ»ΡŒΡ‚Π°Ρ‚, Π»ΠΈΠ±ΠΎ ΠΎΡ‚ΠΌΠ΅Π½Ρƒ обСщания.
52 52 /// </summary>
53 53 /// <param name="handler">ΠžΠ±Ρ€Π°Π±ΠΎΡ‚Ρ‡ΠΈΠΊ.</param>
54 54 /// <remarks>ПослС ΠΎΠ±Ρ€Π°Π±ΠΎΡ‚ΠΊΠ΅ ошибки, ΠΎΠ½Π° пСрСдаСтся дальшС.</remarks>
55 IPromise Finally(Action handler);
55 IPromise Anyway(Action handler);
56 56 /// <summary>
57 57 /// ΠžΠ±Ρ€Π°Π±ΠΎΡ‚Ρ‡ΠΈΠΊ для рСгистрации ΠΎΡ‚ΠΌΠ΅Π½Ρ‹ обСщания, событиС ΠΎΡ‚ΠΌΠ΅Π½Ρ‹ Π½Π΅ ΠΌΠΎΠΆΠ΅Ρ‚ Π±Ρ‹Ρ‚ΡŒ ΠΏΠΎΠ΄Π°Π²Π»Π΅Π½ΠΎ.
58 58 /// </summary>
59 59 /// <returns>НовоС ΠΎΠ±Π΅Ρ‰Π°Π½ΠΈΠ΅, связанноС с Ρ‚Π΅ΠΊΡƒΡ‰ΠΈΠΌ.</returns>
60 60 /// <param name="handler">ΠžΠ±Ρ€Π°Π±ΠΎΡ‚Ρ‡ΠΈΠΊ события.</param>
61 61 /// <remarks>Если ΠΎΠ±Ρ€Π°Π±ΠΎΡ‚Ρ‡ΠΈΠΊ Π²Ρ‹Π·Ρ‹Π²Π°Π΅Ρ‚ ΠΈΡΠΊΠ»ΡŽΡ‡Π΅Π½ΠΈΠ΅, Ρ‚ΠΎ ΠΎΠ½ΠΎ пСрСдаСтся ΠΎΠ±Ρ€Π°Π±ΠΎΡ‚Ρ‡ΠΈΠΊΡƒ ошибки, Ρ€Π΅Π·ΡƒΠ»ΡŒΡ‚Π°Ρ‚ Ρ€Π°Π±ΠΎΡ‚Ρ‹
62 62 /// ΠΊΠΎΡ‚ΠΎΡ€ΠΎΠ³ΠΎ Π±ΡƒΠ΄Π΅Ρ‚ ΠΏΠ΅Ρ€Π΅Π΄Π°Π½ связанному ΠΎΠ±Π΅Ρ‰Π°Π½ΠΈΡŽ</remarks>
63 63 IPromise Cancelled(Action handler);
64 64
65 65 /// <summary>
66 66 /// ΠŸΡ€Π΅ΠΎΠ±Ρ€Π°Π·ΡƒΠ΅Ρ‚ Ρ€Π΅Π·ΡƒΠ»ΡŒΡ‚Π°Ρ‚ обСщания ΠΊ Π·Π°Π΄Π°Π½Π½ΠΎΠΌΡƒ Ρ‚ΠΈΠΏΡƒ ΠΈ Π²ΠΎΠ·Π²Ρ€Π°Ρ‰Π°Π΅Ρ‚ Π½ΠΎΠ²ΠΎΠ΅ ΠΎΠ±Π΅Ρ‰Π°Π½ΠΈΠ΅.
67 67 /// </summary>
68 68 IPromise<T> Cast<T>();
69 69
70 70 /// <summary>
71 71 /// Π‘ΠΈΠ½Ρ…Ρ€ΠΎΠ½ΠΈΠ·ΠΈΡ€ΡƒΠ΅Ρ‚ Ρ‚Π΅ΠΊΡƒΡ‰ΠΈΠΉ ΠΏΠΎΡ‚ΠΎΠΊ с ΠΎΠ±Π΅Ρ‰Π°Π½ΠΈΠ΅ΠΌ.
72 72 /// </summary>
73 73 void Join();
74 74 /// <summary>
75 75 /// Π‘ΠΈΠ½Ρ…Ρ€ΠΎΠ½ΠΈΠ·ΠΈΡ€ΡƒΠ΅Ρ‚ Ρ‚Π΅ΠΊΡƒΡ‰ΠΈΠΉ ΠΏΠΎΡ‚ΠΎΠΊ с ΠΎΠ±Π΅Ρ‰Π°Π½ΠΈΠ΅ΠΌ.
76 76 /// </summary>
77 77 /// <param name="timeout">ВрСмя оТидания, ΠΏΠΎ Π΅Π³ΠΎ ΠΈΡΡ‚Π΅Ρ‡Π΅Π½ΠΈΡŽ Π²ΠΎΠ·Π½ΠΈΠΊΠ½Π΅Ρ‚ ΠΈΡΠΊΠ»ΡŽΡ‡Π΅Π½ΠΈΠ΅.</param>
78 78 /// <exception cref="TimeoutException">ΠŸΡ€Π΅Π²Ρ‹ΡˆΠ΅Π½ΠΎ врСмя оТидания.</exception>
79 79 void Join(int timeout);
80 80
81 81 }
82 82 }
@@ -1,37 +1,43
1 1 using System;
2 2 using System.Collections.Generic;
3 3 using System.Linq;
4 4 using System.Text;
5 5
6 6 namespace Implab {
7 public interface IPromise<T>: IPromise {
7 public interface IPromise<T> : IPromise {
8 8
9 9 new T Join();
10 10
11 11 new T Join(int timeout);
12 12
13 void Last(ResultHandler<T> success, ErrorHandler error, Action cancel);
14
15 void Last(ResultHandler<T> success, ErrorHandler error);
16
17 void Last(ResultHandler<T> success);
18
13 19 IPromise<T> Then(ResultHandler<T> success, ErrorHandler<T> error, Action cancel);
14 20
15 21 IPromise<T> Then(ResultHandler<T> success, ErrorHandler<T> error);
16 22
17 23 IPromise<T> Then(ResultHandler<T> success);
18 24
19 void Last(ResultHandler<T> success, ErrorHandler error, Action cancel);
20 void Last(ResultHandler<T> success, ErrorHandler error);
21 void Last(ResultHandler<T> success);
25 IPromise<T2> Then<T2>(ResultMapper<T, T2> mapper, ErrorHandler<T2> error, Action cancel);
26
27 IPromise<T2> Then<T2>(ResultMapper<T, T2> mapper, ErrorHandler<T2> error);
28
29 IPromise<T2> Then<T2>(ResultMapper<T, T2> mapper);
30
31 IPromise<T2> Chain<T2>(ResultMapper<T, IPromise<T2>> chained, ErrorHandler<IPromise<T2>> error, Action cancel);
32
33 IPromise<T2> Chain<T2>(ResultMapper<T, IPromise<T2>> chained, ErrorHandler<IPromise<T2>> error);
34
35 IPromise<T2> Chain<T2>(ResultMapper<T, IPromise<T2>> chained);
22 36
23 37 IPromise<T> Error(ErrorHandler<T> error);
24 38
25 IPromise<T2> Then<T2>(ResultMapper<T,T2> mapper, ErrorHandler<T> error);
26
27 IPromise<T2> Then<T2>(ResultMapper<T,T2> mapper);
28
29 IPromise<T2> Then<T2>(ChainedOperation<T, T2> chained, ErrorHandler<T> error);
30
31 IPromise<T2> Then<T2>(ChainedOperation<T, T2> chained);
32
33 39 new IPromise<T> Cancelled(Action handler);
34 40
35 new IPromise<T> Finally(Action handler);
41 new IPromise<T> Anyway(Action handler);
36 42 }
37 43 }
@@ -1,193 +1,193
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 m_promise.Finally(Dispose);
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 m_promise.Finally(Dispose);
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 public static IPromise<TDst[]> ChainedMap<TSrc, TDst>(this TSrc[] source, ChainedOperation<TSrc, TDst> transform, int threads) {
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 156 var semaphore = new Semaphore(threads, threads);
157 157
158 158 // Analysis disable AccessToDisposedClosure
159 159 AsyncPool.InvokeNewThread(() => {
160 160 for (int i = 0; i < source.Length; i++) {
161 161 if(promise.IsResolved)
162 162 break; // stop processing in case of error or cancellation
163 163 var idx = i;
164 164
165 165 semaphore.WaitOne();
166 166 try {
167 167 var p1 = transform(source[i]);
168 p1.Finally(() => semaphore.Release());
168 p1.Anyway(() => semaphore.Release());
169 169 p1.Then(
170 170 x => {
171 171 res[idx] = x;
172 172 var left = Interlocked.Decrement(ref pending);
173 173 if (left == 0)
174 174 promise.Resolve(res);
175 175 },
176 176 e => {
177 177 promise.Reject(e);
178 178 throw new TransientPromiseException(e);
179 179 }
180 180 );
181 181
182 182 } catch (Exception e) {
183 183 promise.Reject(e);
184 184 }
185 185 }
186 186 return 0;
187 187 });
188 188
189 return promise.Finally(semaphore.Dispose);
189 return promise.Anyway(semaphore.Dispose);
190 190 }
191 191
192 192 }
193 193 }
@@ -1,764 +1,820
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 public delegate IPromise<TNew> ChainedOperation<in TSrc,TNew>(TSrc result);
15 14
16 15 /// <summary>
17 16 /// Класс для асинхронного получСния Ρ€Π΅Π·ΡƒΠ»ΡŒΡ‚Π°Ρ‚ΠΎΠ². Π’Π°ΠΊ Π½Π°Π·Ρ‹Π²Π°Π΅ΠΌΠΎΠ΅ "ΠΎΠ±Π΅Ρ‰Π°Π½ΠΈΠ΅".
18 17 /// </summary>
19 18 /// <typeparam name="T">Π’ΠΈΠΏ ΠΏΠΎΠ»ΡƒΡ‡Π°Π΅ΠΌΠΎΠ³ΠΎ Ρ€Π΅Π·ΡƒΠ»ΡŒΡ‚Π°Ρ‚Π°</typeparam>
20 19 /// <remarks>
21 20 /// <para>БСрвис ΠΏΡ€ΠΈ ΠΎΠ±Ρ€Π°Ρ‰Π΅Π½ΠΈΠΈ ΠΊ Π΅Π³ΠΎ ΠΌΠ΅Ρ‚ΠΎΠ΄Ρƒ Π΄Π°Π΅Ρ‚ ΠΎΠ±Π΅Ρ‰Π°ΠΈΠ½ΠΈΠ΅ ΠΎ Π²Ρ‹ΠΏΠΎΠ»Π½Π΅Π½ΠΈΠΈ ΠΎΠΏΠ΅Ρ€Π°Ρ†ΠΈΠΈ,
22 21 /// ΠΊΠ»ΠΈΠ΅Π½Ρ‚ ΠΏΠΎΠ»ΡƒΡ‡ΠΈΠ² Ρ‚Π°ΠΊΠΎΠ΅ ΠΎΠ±Π΅Ρ‰Π°Π½ΠΈΠ΅ ΠΌΠΎΠΆΠ΅Ρ‚ ΡƒΡΡ‚Π°Π½ΠΎΠ²ΠΈΡ‚ΡŒ ряд ΠΎΠ±Ρ€Π°Ρ‚Π½Ρ‹Ρ… Π²Ρ‹Π·ΠΎΠ²ΠΎ для получСния
23 22 /// событий выполнСния обСщания, Ρ‚ΠΎΠ΅ΡΡ‚ΡŒ Π·Π°Π²Π΅Ρ€ΡˆΠ΅Π½ΠΈΡ ΠΎΠΏΠ΅Ρ€Π°Ρ†ΠΈΠΈ ΠΈ прСдоставлСнии Ρ€Π΅Π·ΡƒΠ»ΡŒΡ‚Π°Ρ‚ΠΎΠ².</para>
24 23 /// <para>
25 24 /// ΠžΠ±Π΅Ρ‰Π΅Π½ΠΈΠ΅ ΠΌΠΎΠΆΠ΅Ρ‚ Π±Ρ‹Ρ‚ΡŒ ΠΊΠ°ΠΊ Π²Ρ‹ΠΏΠΎΠ»Π½Π΅Π½ΠΎ, Ρ‚Π°ΠΊ ΠΈ Π²Ρ‹ΠΏΠΎΠ»Π½Π΅Π½ΠΎ с ошибкой. Для подписки Π½Π°
26 25 /// Π΄Π°Π½Π½Ρ‹Π΅ события ΠΊΠ»ΠΈΠ΅Π½Ρ‚ Π΄ΠΎΠ»ΠΆΠ΅Π½ ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚ΡŒ ΠΌΠ΅Ρ‚ΠΎΠ΄Ρ‹ <c>Then</c>.
27 26 /// </para>
28 27 /// <para>
29 28 /// БСрвис, Π² свою ΠΎΡ‡Π΅Ρ€Π΅Π΄ΡŒ, ΠΏΠΎ ΠΎΠΊΠΎΠ½Ρ‡Π°Π½ΠΈΡŽ выполнСния ΠΎΠΏΠ΅Ρ€Π°Ρ†ΠΈΠΈ (Π²ΠΎΠ·ΠΌΠΎΠΆΠ½ΠΎ с ошибкой),
30 29 /// ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΠ΅Ρ‚ ΠΌΠ΅Ρ‚ΠΎΠ΄Ρ‹ <c>Resolve</c> Π»ΠΈΠ±ΠΎ <c>Reject</c> для оповСщСния ΠΊΠ»ΠΈΠ΅Ρ‚Π½Π° ΠΎ
31 30 /// Π²Ρ‹ΠΏΠΎΠ»Π½Π΅Π½ΠΈΠΈ обСщания.
32 31 /// </para>
33 32 /// <para>
34 33 /// Если сСрвСр успСл Π²Ρ‹ΠΏΠΎΠ»Π½ΠΈΡ‚ΡŒ ΠΎΠ±Π΅Ρ‰Π°Π½ΠΈΠ΅ Π΅Ρ‰Π΅ Π΄ΠΎ Ρ‚ΠΎΠ³ΠΎ, ΠΊΠ°ΠΊ ΠΊΠ»ΠΈΠ΅Π½Ρ‚ Π½Π° Π½Π΅Π³ΠΎ подписался,
35 34 /// Ρ‚ΠΎ Π² ΠΌΠΎΠΌΠ΅Π½Ρ‚ подписки ΠΊΠ»ΠΈΠ΅Π½Ρ‚Π° Π±ΡƒΠ΄ΡƒΡ‚ Π²Ρ‹Π·Π²Π°Π½Ρ‹ ΡΠΎΠΎΡ‚Π²Π΅Ρ‚ΡΠ²ΡƒΡŽΡ‰ΠΈΠ΅ события Π² синхронном
36 35 /// Ρ€Π΅ΠΆΠΈΠΌΠ΅ ΠΈ ΠΊΠ»ΠΈΠ΅Π½Ρ‚ Π±ΡƒΠ΄Π΅Ρ‚ ΠΎΠΏΠΎΠ²Π΅Ρ‰Π΅Π½ Π² любом случаС. Π˜Π½Π°Ρ‡Π΅, ΠΎΠ±Ρ€Π°Π±ΠΎΡ‚Ρ‡ΠΈΠΊΠΈ Π΄ΠΎΠ±Π°Π²Π»ΡΡŽΡ‚ΡΡ Π²
37 36 /// список Π² порядкС подписания ΠΈ Π² этом ΠΆΠ΅ порядкС ΠΎΠ½ΠΈ Π±ΡƒΠ΄ΡƒΡ‚ Π²Ρ‹Π·Π²Π°Π½Ρ‹ ΠΏΡ€ΠΈ Π²Ρ‹ΠΏΠΎΠ»Π½Π΅Π½ΠΈΠΈ
38 37 /// обСщания.
39 38 /// </para>
40 39 /// <para>
41 40 /// ΠžΠ±Ρ€Π°Π±Π°Ρ‚Ρ‹Π²Π°Ρ Ρ€Π΅Π·ΡƒΠ»ΡŒΡ‚Π°Ρ‚Ρ‹ обСщания ΠΌΠΎΠΆΠ½ΠΎ ΠΏΡ€Π΅ΠΎΠ±Ρ€Π°Π·ΠΎΠ²Ρ‹Π²Π°Ρ‚ΡŒ Ρ€Π΅Π·ΡƒΠ»ΡŒΡ‚Π°Ρ‚Ρ‹ Π»ΠΈΠ±ΠΎ ΠΈΠ½ΠΈΡ†ΠΈΠΈΡ€ΠΎΠ²Π°Ρ‚ΡŒ
42 41 /// связанныС асинхронныС ΠΎΠΏΠ΅Ρ€Π°Ρ†ΠΈΠΈ, ΠΊΠΎΡ‚ΠΎΡ€Ρ‹Π΅ Ρ‚Π°ΠΊΠΆΠ΅ Π²ΠΎΠ·Π²Ρ€Π°Ρ‰Π°ΡŽΡ‚ обСщания. Для этого слСдуСт
43 42 /// ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚ΡŒ ΡΠΎΠΎΡ‚Π²Π΅Ρ‚ΡΡ‚Π²ΡƒΡŽΡ‰ΡƒΡŽ Ρ„ΠΎΡ€ΠΌΡƒ ΠΌΠ΅Ρ‚ΠΎΠ΄Π΅ <c>Then</c>.
44 43 /// </para>
45 44 /// <para>
46 45 /// Π’Π°ΠΊΠΆΠ΅ Ρ…ΠΎΡ€ΠΎΡˆΠΈΠΌ ΠΏΡ€Π°Π²ΠΈΠ»ΠΎΠΌ являСтся Ρ‚ΠΎ, Ρ‡Ρ‚ΠΎ <c>Resolve</c> ΠΈ <c>Reject</c> Π΄ΠΎΠ»ΠΆΠ΅Π½ Π²Ρ‹Π·Ρ‹Π²Π°Ρ‚ΡŒ
47 46 /// Ρ‚ΠΎΠ»ΡŒΠΊΠΎ ΠΈΠ½ΠΈΡ†ΠΈΠ°Ρ‚ΠΎΡ€ обСщания ΠΈΠ½Π°Ρ‡Π΅ ΠΌΠΎΠ³ΡƒΡ‚ Π²ΠΎΠ·Π½ΠΈΠΊΠ½ΡƒΡ‚ΡŒ противорСчия.
48 47 /// </para>
49 48 /// </remarks>
50 49 public class Promise<T> : IPromise<T> {
51 50
52 51 protected struct HandlerDescriptor {
53 52 public ResultHandler<T> resultHandler;
54 53 public ErrorHandler<T> errorHandler;
55 54 public Action cancellHandler;
56 55 public Promise<T> medium;
57 56
58 57 public void Resolve(T result) {
59 58 if (resultHandler != null) {
60 59 try {
61 60 resultHandler(result);
62 61 } catch (Exception e) {
63 62 Reject(e);
64 63 return;
65 64 }
66 65 }
67 66 if (medium != null)
68 67 medium.Resolve(result);
69 68 }
70 69
71 70 public void Reject(Exception err) {
72 71 if (errorHandler != null) {
73 72 try {
74 73 var res = errorHandler(err);
75 74 if (medium != null)
76 75 medium.Resolve(res);
77 76 } catch (TransientPromiseException err2) {
78 77 if (medium != null)
79 78 medium.Reject(err2.InnerException);
80 79 } catch (Exception err2) {
81 80 if (medium != null)
82 81 medium.Reject(err2);
83 82 }
84 83 } else if (medium != null)
85 84 medium.Reject(err);
86 85 }
87 86
88 87 public void Cancel() {
89 88 if (cancellHandler != null) {
90 89 try {
91 90 cancellHandler();
92 91 } catch (Exception err) {
93 92 Reject(err);
94 93 return;
95 94 }
96 95 }
97 96 if (medium != null)
98 97 medium.Cancel();
99 98 }
100 99 }
101 100
102 101 const int UNRESOLVED_SATE = 0;
103 102 const int TRANSITIONAL_STATE = 1;
104 103 const int SUCCEEDED_STATE = 2;
105 104 const int REJECTED_STATE = 3;
106 105 const int CANCELLED_STATE = 4;
107 106
108 107 readonly bool m_cancellable;
109 108
110 109 int m_childrenCount = 0;
111 110 int m_state;
112 111 T m_result;
113 112 Exception m_error;
114 113
115 114 readonly MTQueue<HandlerDescriptor> m_handlers = new MTQueue<HandlerDescriptor>();
116 115
117 116 public Promise() {
118 117 m_cancellable = true;
119 118 }
120 119
121 120 public Promise(IPromise parent, bool cancellable) {
122 121 m_cancellable = cancellable;
123 122 if (parent != null)
124 Cancelled(() => {
125 if (parent.IsExclusive)
126 parent.Cancel();
127 });
123 AddHandler(
124 null,
125 null,
126 () => {
127 if (parent.IsExclusive)
128 parent.Cancel();
129 },
130 null
131 );
128 132 }
129 133
130 134 bool BeginTransit() {
131 135 return UNRESOLVED_SATE == Interlocked.CompareExchange(ref m_state, TRANSITIONAL_STATE, UNRESOLVED_SATE);
132 136 }
133 137
134 138 void CompleteTransit(int state) {
135 139 if (TRANSITIONAL_STATE != Interlocked.CompareExchange(ref m_state, state, TRANSITIONAL_STATE))
136 140 throw new InvalidOperationException("Can't complete transition when the object isn't in the transitional state");
137 141 }
138 142
139 143 void WaitTransition() {
140 144 while (m_state == TRANSITIONAL_STATE) {
141 145 /* noop */
142 146 }
143 147 }
144 148
145 149 public bool IsResolved {
146 150 get {
147 151 return m_state > 1;
148 152 }
149 153 }
150 154
151 155 public bool IsCancelled {
152 156 get {
153 157 return m_state == CANCELLED_STATE;
154 158 }
155 159 }
156 160
157 161 public Type PromiseType {
158 162 get { return typeof(T); }
159 163 }
160 164
161 165 /// <summary>
162 166 /// ВыполняСт ΠΎΠ±Π΅Ρ‰Π°Π½ΠΈΠ΅, сообщая ΠΎΠ± ΡƒΡΠΏΠ΅ΡˆΠ½ΠΎΠΌ Π²Ρ‹ΠΏΠΎΠ»Π½Π΅Π½ΠΈΠΈ.
163 167 /// </summary>
164 168 /// <param name="result">Π Π΅Π·ΡƒΠ»ΡŒΡ‚Π°Ρ‚ выполнСния.</param>
165 169 /// <exception cref="InvalidOperationException">Π”Π°Π½Π½ΠΎΠ΅ ΠΎΠ±Π΅Ρ‰Π°Π½ΠΈΠ΅ ΡƒΠΆΠ΅ Π²Ρ‹ΠΏΠΎΠ»Π½Π΅Π½ΠΎ</exception>
166 170 public void Resolve(T result) {
167 171 if (BeginTransit()) {
168 172 m_result = result;
169 173 CompleteTransit(SUCCEEDED_STATE);
170 174 OnStateChanged();
171 175 } else {
172 176 WaitTransition();
173 177 if (m_state != CANCELLED_STATE)
174 178 throw new InvalidOperationException("The promise is already resolved");
175 179 }
176 180 }
177 181
178 182 /// <summary>
179 183 /// ВыполняСт ΠΎΠ±Π΅Ρ‰Π°Π½ΠΈΠ΅, сообщая ΠΎΠ± ΡƒΡΠΏΠ΅ΡˆΠ½ΠΎΠΌ Π²Ρ‹ΠΏΠΎΠ»Π½Π΅Π½ΠΈΠΈ. Π Π΅Π·ΡƒΠ»ΡŒΡ‚Π°Ρ‚ΠΎΠΌ выполнСния Π±ΡƒΠ΄Π΅Ρ‚ пустоС значСния.
180 184 /// </summary>
181 185 /// <remarks>
182 186 /// Π”Π°Π½Π½Ρ‹ΠΉ Π²Π°Ρ€ΠΈΠ°Π½Ρ‚ ΡƒΠ΄ΠΎΠ±Π΅Π½ Π² случаях, ΠΊΠΎΠ³Π΄Π° интСрСсСн Ρ„Π°ΠΊΡ‚ выполнСния ΠΎΠΏΠ΅Ρ€Π°Ρ†ΠΈΠΈ, Π½Π΅ΠΆΠ΅Π»ΠΈ ΠΏΠΎΠ»ΡƒΡ‡Π΅Π½Π½ΠΎΠ΅ Π·Π½Π°Ρ‡Π΅Π½ΠΈΠ΅.
183 187 /// </remarks>
184 188 public void Resolve() {
185 189 Resolve(default(T));
186 190 }
187 191
188 192 /// <summary>
189 193 /// ВыполняСт ΠΎΠ±Π΅Ρ‰Π°Π½ΠΈΠ΅, сообщая ΠΎΠ± ошибкС
190 194 /// </summary>
191 195 /// <remarks>
192 196 /// ΠŸΠΎΡΠΊΠΎΠ»ΡŒΠΊΡƒ ΠΎΠ±Π΅Ρ‰Π°Π½ΠΈΠ΅ Π΄ΠΎΠ»ΠΆΠ½ΠΎ Ρ€Π°Π±ΠΎΡ‚Π°Ρ‚ΡŒ Π² ΠΌΠ½ΠΎΠ³ΠΎΠΏΡ‚ΠΎΡ‡Π½ΠΎΠΉ срСдС, ΠΏΡ€ΠΈ Π΅Π³ΠΎ Π²Ρ‹ΠΏΠΎΠ»Π½Π΅Π½ΠΈΠΈ сразу нСсколько ΠΏΠΎΡ‚ΠΎΠΊΠΎΠ²
193 197 /// ΠΌΠΎΠ³Ρƒ Π²Π΅Ρ€Π½ΡƒΡ‚ΡŒ ΠΎΡˆΠΈΠ±ΠΊΡƒ, ΠΏΡ€ΠΈ этом Ρ‚ΠΎΠ»ΡŒΠΊΠΎ пСрвая Π±ΡƒΠ΄Π΅Ρ‚ использована Π² качСствС Ρ€Π΅Π·ΡƒΠ»ΡŒΡ‚Π°Ρ‚Π°, ΠΎΡΡ‚Π°Π»ΡŒΠ½Ρ‹Π΅
194 198 /// Π±ΡƒΠ΄ΡƒΡ‚ ΠΏΡ€ΠΎΠΈΠ³Π½ΠΎΡ€ΠΈΡ€ΠΎΠ²Π°Π½Ρ‹.
195 199 /// </remarks>
196 200 /// <param name="error">Π˜ΡΠΊΠ»ΡŽΡ‡Π΅Π½ΠΈΠ΅ возникшСС ΠΏΡ€ΠΈ Π²Ρ‹ΠΏΠΎΠ»Π½Π΅Π½ΠΈΠΈ ΠΎΠΏΠ΅Ρ€Π°Ρ†ΠΈΠΈ</param>
197 201 /// <exception cref="InvalidOperationException">Π”Π°Π½Π½ΠΎΠ΅ ΠΎΠ±Π΅Ρ‰Π°Π½ΠΈΠ΅ ΡƒΠΆΠ΅ Π²Ρ‹ΠΏΠΎΠ»Π½Π΅Π½ΠΎ</exception>
198 202 public void Reject(Exception error) {
199 203 if (BeginTransit()) {
200 204 m_error = error;
201 205 CompleteTransit(REJECTED_STATE);
202 206 OnStateChanged();
203 207 } else {
204 208 WaitTransition();
205 209 if (m_state == SUCCEEDED_STATE)
206 210 throw new InvalidOperationException("The promise is already resolved");
207 211 }
208 212 }
209 213
210 214 /// <summary>
211 215 /// ΠžΡ‚ΠΌΠ΅Π½ΡΠ΅Ρ‚ ΠΎΠΏΠ΅Ρ€Π°Ρ†ΠΈΡŽ, Ссли это Π²ΠΎΠ·ΠΌΠΎΠΆΠ½ΠΎ.
212 216 /// </summary>
213 /// <returns><c>true</c> ΠžΠΏΠ΅Ρ€Π°Ρ†ΠΈΡ Π±Ρ‹Π»Π° ΠΎΡ‚ΠΌΠ΅Π½Π΅Π½Π°, ΠΎΠ±Ρ€Π°Π±ΠΎΡ‚Ρ‡ΠΈΠΊΠΈ Π½Π΅ Π±ΡƒΠ΄ΡƒΡ‚ Π²Ρ‹Π·Π²Π°Π½Ρ‹.<c>false</c> ΠΎΡ‚ΠΌΠ΅Π½Π° Π½Π΅ Π²ΠΎΠ·ΠΌΠΎΠΆΠ½Π°, ΠΏΠΎΡΠΊΠΎΠ»ΡŒΠΊΡƒ ΠΎΠ±Π΅Ρ‰Π°Π½ΠΈΠ΅ ΡƒΠΆΠ΅ Π²Ρ‹ΠΏΠΎΠ»Π½Π΅Π½ΠΎ ΠΈ ΠΎΠ±Ρ€Π°Π±ΠΎΡ‚Ρ‡ΠΈΠΊΠΈ ΠΎΡ‚Ρ€Π°Π±ΠΎΡ‚Π°Π»ΠΈ.</returns>
214 public bool Cancel() {
217 /// <remarks>Для опрСдСлСния Π±Ρ‹Π»Π° Π»ΠΈ опСрация ΠΎΡ‚ΠΌΠ΅Π½Π΅Π½Π° слСдуСт ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚ΡŒ свойство <see cref="IsCancelled"/>.</remarks>
218 public void Cancel() {
215 219 if (m_cancellable && BeginTransit()) {
216 220 CompleteTransit(CANCELLED_STATE);
217 221 OnStateChanged();
218 return true;
219 222 }
220 return false;
221 223 }
222 224
223 // сдСлано для Π²ΠΎΠ·Π²Ρ€Π°Ρ‰Π°Π΅ΠΌΠΎΠ³ΠΎ Ρ‚ΠΈΠΏΠ° void
224 protected void InternalCancel() {
225 Cancel();
226 }
227
228
229 225 public IPromise<T> Then(ResultHandler<T> success, ErrorHandler<T> error, Action cancel) {
230 226 if (success == null && error == null && cancel == null)
231 227 return this;
232 228
233 229 var medium = new Promise<T>(this, true);
234 230
235 231 AddHandler(success, error, cancel, medium);
236 232
237 233 return medium;
238 234 }
239 235
240 236 /// <summary>
241 237 /// Adds new handlers to this promise.
242 238 /// </summary>
243 239 /// <param name="success">The handler of the successfully completed operation.
244 240 /// This handler will recieve an operation result as a parameter.</param>
245 241 /// <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>
246 242 /// <returns>The new promise chained to this one.</returns>
247 243 public IPromise<T> Then(ResultHandler<T> success, ErrorHandler<T> error) {
248 244 if (success == null && error == null)
249 245 return this;
250 246
251 247 var medium = new Promise<T>(this, true);
252 248
253 249 AddHandler(success, error, null, medium);
254 250
255 251 return medium;
256 252 }
257 253
258 public IPromise Then(Action success, ErrorHandler error, Action cancel) {
259 return Then(
260 x => success(),
261 e => {
262 error(e);
263 return default(T);
264 },
265 cancel
266 );
267 }
268
269 public IPromise Then(Action success, ErrorHandler error) {
270 return Then(
271 x => success(),
272 e => {
273 error(e);
274 return default(T);
275 }
276 );
277 }
278
279 public IPromise Then(Action success) {
280 return Then(x => success());
281 }
254
282 255
283 256
284 257 public IPromise<T> Then(ResultHandler<T> success) {
285 258 if (success == null)
286 259 return this;
287 260
288 261 var medium = new Promise<T>(this, true);
289 262
290 263 AddHandler(success, null, null, medium);
291 264
292 265 return medium;
293 266 }
294 267
268 /// <summary>
269 /// ПослСдний ΠΎΠ±Ρ€Π°Π±ΠΎΡ‚Ρ‡ΠΈΠΊ Π² Ρ†Π΅ΠΏΠΎΡ‡ΠΊΠΈ ΠΎΠ±Π΅Ρ‰Π°Π½ΠΈΠΉ.
270 /// </summary>
271 /// <param name="success"></param>
272 /// <param name="error"></param>
273 /// <param name="cancel"></param>
274 /// <remarks>
275 /// <para>
276 /// Π”Π°Π½Π½Ρ‹ΠΉ ΠΌΠ΅Ρ‚ΠΎΠ΄ Π½Π΅ создаСт связанного с Ρ‚Π΅ΠΊΡƒΡ‰ΠΈΠΌ обСщания ΠΈ ΠΏΡ€Π΅Π΄Π½Π°Π·Π½Π°Ρ‡Π΅Π½ для окончания
277 /// фсинхронной Ρ†Π΅ΠΏΠΎΡ‡ΠΊΠΈ.
278 /// </para>
279 /// <para>
280 /// Если Π΄Π°Π½Π½Ρ‹ΠΉ ΠΌΠ΅Ρ‚ΠΎΠ΄ Π²Ρ‹Π·Π²Π°Ρ‚ΡŒ нСсколько Ρ€Π°Π·, Π»ΠΈΠ±ΠΎ Π΄ΠΎΠ±Π°Π²ΠΈΡ‚ΡŒ Π΄Ρ€ΡƒΠ³ΠΈΠ΅ ΠΎΠ±Ρ€Π°Π±ΠΎΡ‚Ρ‡ΠΈΠΊΠΈ, Ρ‚ΠΎ Ρ†Π΅ΠΏΠΎΡ‡ΠΊΠ°
281 /// Π½Π΅ Π±ΡƒΠ΄Π΅Ρ‚ ΠΎΠ΄ΠΈΠ½ΠΎΡ‡Π½ΠΎΠΉ <see cref="IsExclusive"/> ΠΈ, ΠΊΠ°ΠΊ слСдствиС, Π±ΡƒΠ΄Π΅Ρ‚ Π½Π΅Π²ΠΎΠ·ΠΌΠΎΠΆΠ½Π° ΠΎΡ‚ΠΌΠ΅Π½Π°
282 /// всСй Ρ†Π΅ΠΏΠΈ ΠΎΠ±Π΅Ρ‰Π°Π½ΠΈΠΉ снизу (с самого послСднСго обСщания).
283 /// </para>
284 /// </remarks>
295 285 public void Last(ResultHandler<T> success, ErrorHandler error, Action cancel) {
296 286 if (success == null && error == null && cancel == null)
297 287 return;
298 288
299 289 ErrorHandler<T> errorHandler = null;
300 290 if (error != null)
301 291 errorHandler = err => {
302 292 error(err);
303 293 return default(T);
304 294 };
305 295 AddHandler(success, errorHandler, cancel, null);
306 296 }
307 297
308 298 public void Last(ResultHandler<T> success, ErrorHandler error) {
309 299 Last(success, error, null);
310 300 }
311 301
312 302 public void Last(ResultHandler<T> success) {
313 303 Last(success, null, null);
314 304 }
315 305
316 public void Last(Action success,ErrorHandler error, Action cancel) {
317 Last(x => success(), error, cancel);
318 }
319
320 public void Last(Action success,ErrorHandler error) {
321 Last(x => success(), error, null);
322 }
323
324 public void Last(Action success) {
325 Last(x => success(), null, null);
326 }
327
328 306 public IPromise Error(ErrorHandler error) {
329 307 if (error == null)
330 308 return this;
331 309
332 310 var medium = new Promise<T>(this, true);
333 311
334 312 AddHandler(
335 313 null,
336 314 e => {
337 315 error(e);
338 316 return default(T);
339 317 },
340 318 null,
341 319 medium
342 320 );
343 321
344 322 return medium;
345 323 }
346 324
347 325 /// <summary>
348 326 /// Handles error and allows to keep the promise.
349 327 /// </summary>
350 328 /// <remarks>
351 329 /// If the specified handler throws an exception, this exception will be used to reject the promise.
352 330 /// </remarks>
353 331 /// <param name="handler">The error handler which returns the result of the promise.</param>
354 332 /// <returns>New promise.</returns>
355 333 public IPromise<T> Error(ErrorHandler<T> handler) {
356 334 if (handler == null)
357 335 return this;
358 336
359 337 var medium = new Promise<T>(this, true);
360 338
361 339 AddHandler(null, handler, null, medium);
362 340
363 341 return medium;
364 342 }
365 343
366 344 /// <summary>
367 345 /// ΠŸΠΎΠ·Π²ΠΎΠ»ΡΠ΅Ρ‚ ΠΏΡ€Π΅ΠΎΠ±Ρ€Π°Π·ΠΎΠ²Π°Ρ‚ΡŒ Ρ€Π΅Π·ΡƒΠ»ΡŒΡ‚Π°Ρ‚ выполСния ΠΎΠΏΠ΅Ρ€Π°Ρ†ΠΈΠΈ ΠΊ Π½ΠΎΠ²ΠΎΠΌΡƒ Ρ‚ΠΈΠΏΡƒ.
368 346 /// </summary>
369 347 /// <typeparam name="TNew">Новый Ρ‚ΠΈΠΏ Ρ€Π΅Π·ΡƒΠ»ΡŒΡ‚Π°Ρ‚Π°.</typeparam>
370 348 /// <param name="mapper">ΠŸΡ€Π΅ΠΎΠ±Ρ€Π°Π·ΠΎΠ²Π°Π½ΠΈΠ΅ Ρ€Π΅Π·ΡƒΠ»ΡŒΡ‚Π°Ρ‚Π° ΠΊ Π½ΠΎΠ²ΠΎΠΌΡƒ Ρ‚ΠΈΠΏΡƒ.</param>
371 349 /// <param name="error">ΠžΠ±Ρ€Π°Π±ΠΎΡ‚Ρ‡ΠΈΠΊ ошибки. Π”Π°Π½Π½Ρ‹ΠΉ ΠΎΠ±Ρ€Π°Π±ΠΎΡ‚Ρ‡ΠΈΠΊ ΠΏΠΎΠ»ΡƒΡ‡ΠΈΡ‚
372 350 /// ΠΈΡΠΊΠ»ΡŽΡ‡Π΅Π½ΠΈΠ΅ возникшСС ΠΏΡ€ΠΈ Π²Ρ‹ΠΏΠΎΠ»Π½Π΅Π½ΠΈΠΈ ΠΎΠΏΠ΅Ρ€Π°Ρ†ΠΈΠΈ.</param>
373 351 /// <returns>НовоС ΠΎΠ±Π΅Ρ‰Π°Π½ΠΈΠ΅, ΠΊΠΎΡ‚ΠΎΡ€ΠΎΠ΅ Π±ΡƒΠ΄Π΅Ρ‚ Π²Ρ‹ΠΏΠΎΠ»Π½Π΅Π½ΠΎ ΠΏΡ€ΠΈ Π²Ρ‹ΠΏΠΎΠ»Π½Π΅Π½ΠΈΠΈ исходного обСщания.</returns>
374 public IPromise<TNew> Then<TNew>(ResultMapper<T, TNew> mapper, ErrorHandler<T> error) {
375 if (mapper == null)
376 throw new ArgumentNullException("mapper");
352 public IPromise<TNew> Then<TNew>(ResultMapper<T, TNew> mapper, ErrorHandler<TNew> error, Action cancel) {
353 Safe.ArgumentNotNull(mapper, "mapper");
354
355 // создаСм ΠΏΡ€ΠΈΡ†Π΅ΠΏΠ»Π΅Π½Π½ΠΎΠ΅ ΠΎΠ±Π΅Ρ‰Π°Π½ΠΈΠ΅
356 var medium = new Promise<TNew>(this, true);
377 357
378 // создаСм ΠΏΡ€ΠΈΡ†Π΅ΠΏΠ»Π΅Π½Π½ΠΎΠ΅ ΠΎΠ±Π΅Ρ‰Π°Π½ΠΈΠ΅
379 var chained = new Promise<TNew>(this, true);
380
381 ResultHandler<T> resultHandler = result => chained.Resolve(mapper(result));
358 ResultHandler<T> resultHandler = result => medium.Resolve(mapper(result));
382 359 ErrorHandler<T> errorHandler;
383 360 if (error != null)
384 361 errorHandler = e => {
385 362 try {
386 return error(e);
363 medium.Resolve(error(e));
387 364 } catch (Exception e2) {
388 365 // Π² случаС ошибки Π½ΡƒΠΆΠ½ΠΎ ΠΏΠ΅Ρ€Π΅Π΄Π°Ρ‚ΡŒ ΠΈΡΠΊΠ»ΡŽΡ‡Π΅Π½ΠΈΠ΅ дальшС ΠΏΠΎ Ρ†Π΅ΠΏΠΎΡ‡ΠΊΠ΅
389 chained.Reject(e2);
366 medium.Reject(e2);
390 367 }
391 368 return default(T);
392 369 };
393 370 else
394 371 errorHandler = e => {
395 chained.Reject(e);
372 medium.Reject(e);
396 373 return default(T);
397 374 };
398 375
376 Action cancelHandler;
377 if (cancel != null)
378 cancelHandler = () => {
379 cancel();
380 medium.Cancel();
381 };
382 else
383 cancelHandler = medium.Cancel;
384
399 385
400 386 AddHandler(
401 387 resultHandler,
402 388 errorHandler,
403 chained.InternalCancel,
389 cancelHandler,
404 390 null
405 391 );
406 392
407 return chained;
393 return medium;
394 }
395
396 public IPromise<TNew> Then<TNew>(ResultMapper<T, TNew> mapper, ErrorHandler<TNew> error) {
397 return Then(mapper, error, null);
408 398 }
409 399
410 400 public IPromise<TNew> Then<TNew>(ResultMapper<T, TNew> mapper) {
411 return Then(mapper, null);
401 return Then(mapper, null, null);
412 402 }
413 403
414 404 /// <summary>
415 405 /// БцСпляСт нСсколько аснхронных ΠΎΠΏΠ΅Ρ€Π°Ρ†ΠΈΠΉ. Указанная асинхронная опСрация Π±ΡƒΠ΄Π΅Ρ‚ Π²Ρ‹Π·Π²Π°Π½Π° послС
416 406 /// выполнСния Ρ‚Π΅ΠΊΡƒΡ‰Π΅ΠΉ, Π° Ρ€Π΅Π·ΡƒΠ»ΡŒΡ‚Π°Ρ‚ Ρ‚Π΅ΠΊΡƒΡ‰Π΅ΠΉ ΠΎΠΏΠ΅Ρ€Π°Ρ†ΠΈΠΈ ΠΌΠΎΠΆΠ΅Ρ‚ Π±Ρ‹Ρ‚ΡŒ использован для ΠΈΠ½ΠΈΡ†ΠΈΠ°Π»ΠΈΠ·Π°Ρ†ΠΈΠΈ
417 407 /// Π½ΠΎΠ²ΠΎΠΉ ΠΎΠΏΠ΅Ρ€Π°Ρ†ΠΈΠΈ.
418 408 /// </summary>
419 409 /// <typeparam name="TNew">Π’ΠΈΠΏ Ρ€Π΅Π·ΡƒΠ»ΡŒΡ‚Π°Ρ‚Π° ΡƒΠΊΠ°Π·Π°Π½Π½ΠΎΠΉ асинхронной ΠΎΠΏΠ΅Ρ€Π°Ρ†ΠΈΠΈ.</typeparam>
420 410 /// <param name="chained">Асинхронная опСрация, которая Π΄ΠΎΠ»ΠΆΠ½Π° Π±ΡƒΠ΄Π΅Ρ‚ Π½Π°Ρ‡Π°Ρ‚ΡŒΡΡ послС выполнСния Ρ‚Π΅ΠΊΡƒΡ‰Π΅ΠΉ.</param>
421 411 /// <param name="error">ΠžΠ±Ρ€Π°Π±ΠΎΡ‚Ρ‡ΠΈΠΊ ошибки. Π”Π°Π½Π½Ρ‹ΠΉ ΠΎΠ±Ρ€Π°Π±ΠΎΡ‚Ρ‡ΠΈΠΊ ΠΏΠΎΠ»ΡƒΡ‡ΠΈΡ‚
422 412 /// ΠΈΡΠΊΠ»ΡŽΡ‡Π΅Π½ΠΈΠ΅ возникшСС ΠΏΡ€ΠΈ Π²Ρ‹ΠΏΠΎΠ»Π½Π΅Π½ΠΈΠΈ Ρ‚Π΅ΠΊΡƒΠ΅Ρ‰ΠΉ ΠΎΠΏΠ΅Ρ€Π°Ρ†ΠΈΠΈ.</param>
423 413 /// <returns>НовоС ΠΎΠ±Π΅Ρ‰Π°Π½ΠΈΠ΅, ΠΊΠΎΡ‚ΠΎΡ€ΠΎΠ΅ Π±ΡƒΠ΄Π΅Ρ‚ Π²Ρ‹ΠΏΠΎΠ»Π½Π΅Π½ΠΎ ΠΏΠΎ ΠΎΠΊΠΎΠ½Ρ‡Π°Π½ΠΈΡŽ ΡƒΠΊΠ°Π·Π°Π½Π½ΠΎΠΉ аснхронной ΠΎΠΏΠ΅Ρ€Π°Ρ†ΠΈΠΈ.</returns>
424 public IPromise<TNew> Then<TNew>(ChainedOperation<T, TNew> chained, ErrorHandler<T> error) {
414 public IPromise<TNew> Chain<TNew>(ResultMapper<T, IPromise<TNew>> chained, ErrorHandler<IPromise<TNew>> error, Action cancel) {
415
416 Safe.ArgumentNotNull(chained, "chained");
425 417
426 418 // ΠΏΡ€ΠΎΠ±Π»Π΅ΠΌΠ° Π² Ρ‚ΠΎΠΌ, Ρ‡Ρ‚ΠΎ Π½Π° ΠΌΠΎΠΌΠ΅Π½Ρ‚ связывания Π΅Ρ‰Π΅ Π½Π΅ Π½Π°Ρ‡Π°Ρ‚Π° асинхронная опСрация, поэтому Π½ΡƒΠΆΠ½ΠΎ
427 419 // ΡΠΎΠ·Π΄Π°Ρ‚ΡŒ посрСдника, ΠΊ ΠΊΠΎΡ‚ΠΎΡ€ΠΎΠΌΡƒ Π±ΡƒΠ΄ΡƒΡ‚ ΠΏΠΎΠ΄Π²Ρ‹Π·ΡΠ²Π°Ρ‚ΡŒΡΡ ΡΠ»Π΅Π΄ΡƒΡŽΡ‰ΠΈΠ΅ ΠΎΠ±Ρ€Π°Π±ΠΎΡ‚Ρ‡ΠΈΠΊΠΈ.
428 420 // ΠΊΠΎΠ³Π΄Π° Π±ΡƒΠ΄Π΅Ρ‚ Π²Ρ‹ΠΏΠΎΠ»Π½Π΅Π½Π° Ρ€Π΅Π°Π»ΡŒΠ½Π°Ρ асинхронная опСрация, ΠΎΠ½Π° ΠΎΠ±Ρ€Π°Ρ‚ΠΈΡ‚ΡŒΡΡ ΠΊ посрСднику, Ρ‡Ρ‚ΠΎΠ±Ρ‹
429 421 // ΠΏΠ΅Ρ€Π΅Π΄Π°Ρ‚ΡŒ Ρ‡Π΅Ρ€Π΅Π· Π½Π΅Π³ΠΎ Ρ€Π΅Π·ΡƒΠ»ΡŒΡ‚Π°Ρ‚Ρ‹ Ρ€Π°Π±ΠΎΡ‚Ρ‹.
430 422 var medium = new Promise<TNew>(this, true);
431 423
432 424 ResultHandler<T> resultHandler = delegate(T result) {
433 425 if (medium.IsCancelled)
434 426 return;
435 427
436 428 var promise = chained(result);
437 429
438 promise.Then(
430 promise.Last(
439 431 medium.Resolve,
440 err => {
441 medium.Reject(err);
442 throw new TransientPromiseException(err);
443 }
432 medium.Reject,
433 () => medium.Reject(new OperationCanceledException()) // внСшняя ΠΎΡ‚ΠΌΠ΅Π½Π° связанной ΠΎΠΏΠ΅Ρ€Π°Ρ†ΠΈΠΈ рассматриваСтся ΠΊΠ°ΠΊ ошибка
444 434 );
445 435
446 436 // notify chained operation that it's not needed anymore
447 437 // порядок Π²Ρ‹Π·ΠΎΠ²Π° Then, Cancelled Π²Π°ΠΆΠ΅Π½, ΠΏΠΎΡΠΊΠΎΠ»ΡŒΠΊΡƒ ΠΎΡ‚ этого
448 438 // зависит IsExclusive
449 439 medium.Cancelled(() => {
450 440 if (promise.IsExclusive)
451 441 promise.Cancel();
452 442 });
453
454 // внСшняя ΠΎΡ‚ΠΌΠ΅Π½Π° связанной ΠΎΠΏΠ΅Ρ€Π°Ρ†ΠΈΠΈ рассматриваСтся ΠΊΠ°ΠΊ ошибка
455 promise.Cancelled(() => medium.Reject(new OperationCanceledException()));
456 443 };
457 444
458 ErrorHandler<T> errorHandler = delegate(Exception e) {
459 if (error != null) {
445 ErrorHandler<T> errorHandler;
446
447 if (error != null)
448 errorHandler = delegate(Exception e) {
460 449 try {
461 return error(e);
450 var promise = error(e);
451
452 promise.Last(
453 medium.Resolve,
454 medium.Reject,
455 () => medium.Reject(new OperationCanceledException()) // внСшняя ΠΎΡ‚ΠΌΠ΅Π½Π° связанной ΠΎΠΏΠ΅Ρ€Π°Ρ†ΠΈΠΈ рассматриваСтся ΠΊΠ°ΠΊ ошибка
456 );
457
458 // notify chained operation that it's not needed anymore
459 // порядок Π²Ρ‹Π·ΠΎΠ²Π° Then, Cancelled Π²Π°ΠΆΠ΅Π½, ΠΏΠΎΡΠΊΠΎΠ»ΡŒΠΊΡƒ ΠΎΡ‚ этого
460 // зависит IsExclusive
461 medium.Cancelled(() => {
462 if (promise.IsExclusive)
463 promise.Cancel();
464 });
462 465 } catch (Exception e2) {
463 466 medium.Reject(e2);
464 return default(T);
465 467 }
466 }
467 // Π² случаС ошибки Π½ΡƒΠΆΠ½ΠΎ ΠΏΠ΅Ρ€Π΅Π΄Π°Ρ‚ΡŒ ΠΈΡΠΊΠ»ΡŽΡ‡Π΅Π½ΠΈΠ΅ дальшС ΠΏΠΎ Ρ†Π΅ΠΏΠΎΡ‡ΠΊΠ΅
468 medium.Reject(e);
469 return default(T);
470 };
468 return default(T);
469 };
470 else
471 errorHandler = err => {
472 medium.Reject(err);
473 return default(T);
474 };
475
476
477 Action cancelHandler;
478 if (cancel != null)
479 cancelHandler = () => {
480 if (cancel != null)
481 cancel();
482 medium.Cancel();
483 };
484 else
485 cancelHandler = medium.Cancel;
471 486
472 487 AddHandler(
473 488 resultHandler,
474 489 errorHandler,
475 medium.InternalCancel,
490 cancelHandler,
476 491 null
477 492 );
478 493
479 494 return medium;
480 495 }
481 496
482 public IPromise<TNew> Then<TNew>(ChainedOperation<T, TNew> chained) {
483 return Then(chained, null);
497 public IPromise<TNew> Chain<TNew>(ResultMapper<T, IPromise<TNew>> chained, ErrorHandler<IPromise<TNew>> error) {
498 return Chain(chained, error, null);
499 }
500
501 public IPromise<TNew> Chain<TNew>(ResultMapper<T, IPromise<TNew>> chained) {
502 return Chain(chained, null, null);
484 503 }
485 504
486 505 public IPromise<T> Cancelled(Action handler) {
487 var medium = new Promise<T>(this, true);
506 var medium = new Promise<T>(this,true);
488 507 AddHandler(null, null, handler, medium);
489 508 return medium;
490 509 }
491 510
492 511 /// <summary>
493 512 /// Adds the specified handler for all cases (success, error, cancel)
494 513 /// </summary>
495 514 /// <param name="handler">The handler that will be called anyway</param>
496 515 /// <returns>self</returns>
497 public IPromise<T> Finally(Action handler) {
498 if (handler == null)
499 throw new ArgumentNullException("handler");
516 public IPromise<T> Anyway(Action handler) {
517 Safe.ArgumentNotNull(handler, "handler");
518
500 519 AddHandler(
501 520 x => handler(),
502 521 e => {
503 522 handler();
504 523 throw new TransientPromiseException(e);
505 524 },
506 525 handler,
507 526 null
508 527 );
509 528 return this;
510 529 }
511 530
512 531 /// <summary>
513 532 /// ΠŸΡ€Π΅ΠΎΠ±Ρ€Π°Π·ΡƒΠ΅Ρ‚ Ρ€Π΅Π·ΡƒΠ»ΡŒΡ‚Π°Ρ‚ обСщания ΠΊ Π½ΡƒΠΆΠ½ΠΎΠΌΡƒ Ρ‚ΠΈΠΏΡƒ
514 533 /// </summary>
515 534 /// <typeparam name="T2"></typeparam>
516 535 /// <returns></returns>
517 536 public IPromise<T2> Cast<T2>() {
518 537 return Then(x => (T2)(object)x, null);
519 538 }
520 539
521 540 /// <summary>
522 541 /// ДоТидаСтся ΠΎΡ‚Π»ΠΎΠΆΠ΅Π½Π½ΠΎΠ³ΠΎ обСщания ΠΈ Π² случаС успСха, Π²ΠΎΠ·Π²Ρ€Π°Ρ‰Π°Π΅Ρ‚
523 542 /// Π΅Π³ΠΎ, Ρ€Π΅Π·ΡƒΠ»ΡŒΡ‚Π°Ρ‚, Π² ΠΏΡ€ΠΎΡ‚ΠΈΠ²Π½ΠΎΠΌ случаС бросаСт ΠΈΡΠΊΠ»ΡŽΡ‡Π΅Π½ΠΈΠ΅.
524 543 /// </summary>
525 544 /// <remarks>
526 545 /// <para>
527 546 /// Если ΠΎΠΆΠΈΠ΄Π°Π½ΠΈΠ΅ обСщания Π±Ρ‹Π»ΠΎ ΠΏΡ€Π΅Ρ€Π²Π°Π½ΠΎ ΠΏΠΎ Ρ‚Π°ΠΉΠΌΠ°ΡƒΡ‚Ρƒ, это Π½Π΅ Π·Π½Π°Ρ‡ΠΈΡ‚,
528 547 /// Ρ‡Ρ‚ΠΎ ΠΎΠ±Π΅Ρ‰Π°Π½ΠΈΠ΅ Π±Ρ‹Π»ΠΎ ΠΎΡ‚ΠΌΠ΅Π½Π΅Π½ΠΎ ΠΈΠ»ΠΈ Ρ‡Ρ‚ΠΎ-Ρ‚ΠΎ Π² этом Ρ€ΠΎΠ΄Π΅, это Ρ‚ΠΎΠ»ΡŒΠΊΠΎ
529 548 /// ΠΎΠ·Π½Π°Ρ‡Π°Π΅Ρ‚, Ρ‡Ρ‚ΠΎ ΠΌΡ‹ Π΅Π³ΠΎ Π½Π΅ доТдались, ΠΎΠ΄Π½Π°ΠΊΠΎ всС зарСгистрированныС
530 549 /// ΠΎΠ±Ρ€Π°Π±ΠΎΡ‚Ρ‡ΠΈΠΊΠΈ, ΠΊΠ°ΠΊ Π±Ρ‹Π»ΠΈ Ρ‚Π°ΠΊ ΠΎΡΡ‚Π°Π»ΠΈΡΡŒ ΠΈ ΠΎΠ½ΠΈ Π±ΡƒΠ΄ΡƒΡ‚ Π²Ρ‹Π·Π²Π°Π½Ρ‹, ΠΊΠΎΠ³Π΄Π°
531 550 /// ΠΎΠ±Π΅Ρ‰Π°Π½ΠΈΠ΅ Π±ΡƒΠ΄Π΅Ρ‚ Π²Ρ‹ΠΏΠΎΠ»Π½Π΅Π½ΠΎ.
532 551 /// </para>
533 552 /// <para>
534 553 /// Π’Π°ΠΊΠΎΠ΅ ΠΏΠΎΠ²Π΅Π΄Π΅Π½ΠΈΠ΅ Π²ΠΏΠΎΠ»Π½Π΅ ΠΎΠΏΡ€Π°Π²Π΄Π°Π½ΠΎ ΠΏΠΎΡΠΊΠΎΠ»ΡŒΠΊΡƒ Ρ‚Π°ΠΉΠΌΠ°ΡƒΡ‚ ΠΌΠΎΠΆΠ΅Ρ‚ ΠΈΡΡ‚Π΅Ρ‡ΡŒ
535 554 /// Π² Ρ‚ΠΎΡ‚ ΠΌΠΎΠΌΠ΅Π½Ρ‚, ΠΊΠΎΠ³Π΄Π° Π½Π°Ρ‡Π°Π»Π°ΡΡŒ ΠΎΠ±Ρ€Π°Π±ΠΎΡ‚ΠΊΠ° Ρ†Π΅ΠΏΠΎΡ‡ΠΊΠΈ ΠΎΠ±Ρ€Π°Π±ΠΎΡ‚Ρ‡ΠΈΠΊΠΎΠ², ΠΈ
536 555 /// ΠΊ Ρ‚ΠΎΠΌΡƒ ΠΆΠ΅ Ρ‚Π΅ΠΊΡƒΡ‰Π΅Π΅ ΠΎΠ±Π΅Ρ‰Π°Π½ΠΈΠ΅ ΠΌΠΎΠΆΠ΅Ρ‚ ΡΡ‚ΠΎΡΡ‚ΡŒ Π² Ρ†Π΅ΠΏΠΎΡ‡ΠΊΠ΅ ΠΎΠ±Π΅Ρ‰Π°Π½ΠΈΠΉ ΠΈ Π΅Π³ΠΎ
537 556 /// ΠΎΡ‚ΠΊΠ»ΠΎΠ½Π΅Π½ΠΈΠ΅ ΠΌΠΎΠΆΠ΅Ρ‚ привСсти ΠΊ Π½Π΅ΠΏΡ€ΠΎΠ³Π½ΠΎΠ·ΠΈΡ€ΡƒΠ΅ΠΌΠΎΠΌΡƒ Ρ€Π΅Π·ΡƒΠ»ΡŒΡ‚Π°Ρ‚Ρƒ.
538 557 /// </para>
539 558 /// </remarks>
540 559 /// <param name="timeout">ВрСмя оТидания</param>
541 560 /// <returns>Π Π΅Π·ΡƒΠ»ΡŒΡ‚Π°Ρ‚ выполнСния обСщания</returns>
542 561 public T Join(int timeout) {
543 562 var evt = new ManualResetEvent(false);
544 Finally(() => evt.Set());
563 Anyway(() => evt.Set());
545 564
546 565 if (!evt.WaitOne(timeout, true))
547 566 throw new TimeoutException();
548 567
549 568 switch (m_state) {
550 569 case SUCCEEDED_STATE:
551 570 return m_result;
552 571 case CANCELLED_STATE:
553 572 throw new OperationCanceledException();
554 573 case REJECTED_STATE:
555 574 throw new TargetInvocationException(m_error);
556 575 default:
557 576 throw new ApplicationException(String.Format("Invalid promise state {0}", m_state));
558 577 }
559 578 }
560 579
561 580 public T Join() {
562 581 return Join(Timeout.Infinite);
563 582 }
564 583
565 584 void AddHandler(ResultHandler<T> success, ErrorHandler<T> error, Action cancel, Promise<T> medium) {
566 585 if (success != null || error != null)
567 586 Interlocked.Increment(ref m_childrenCount);
568 587
569 588 var handler = new HandlerDescriptor {
570 589 resultHandler = success,
571 590 errorHandler = error,
572 591 cancellHandler = cancel,
573 592 medium = medium
574 593 };
575 594
576 595 bool queued;
577 596
578 597 if (!IsResolved) {
579 598 m_handlers.Enqueue(handler);
580 599 queued = true;
581 600 } else {
582 601 // the promise is in resolved state, just invoke the handled with minimum overhead
583 602 queued = false;
584 603 InvokeHandler(handler);
585 604 }
586 605
587 606 if (queued && IsResolved && m_handlers.TryDequeue(out handler))
588 607 // if the promise have been resolved while we was adding handler to the queue
589 608 // we can't guarantee that someone is still processing it
590 609 // therefore we will fetch a handler from the queue and execute it
591 610 // note that fetched handler may be not the one that we have added
592 611 // even we can fetch no handlers at all :)
593 612 InvokeHandler(handler);
594 613 }
595 614
596 615 protected virtual void InvokeHandler(HandlerDescriptor handler) {
597 616 switch (m_state) {
598 617 case SUCCEEDED_STATE:
599 618 handler.Resolve(m_result);
600 619 break;
601 620 case REJECTED_STATE:
602 621 handler.Reject(m_error);
603 622 break;
604 623 case CANCELLED_STATE:
605 624 handler.Cancel();
606 625 break;
607 626 default:
608 627 // do nothing
609 628 return;
610 629 }
611 630 }
612 631
613 632 void OnStateChanged() {
614 633 HandlerDescriptor handler;
615 634 while (m_handlers.TryDequeue(out handler))
616 635 InvokeHandler(handler);
617 636 }
618 637
619 638 public bool IsExclusive {
620 639 get {
621 640 return m_childrenCount <= 1;
622 641 }
623 642 }
624 643
625 644 /// <summary>
626 645 /// ΠžΠ±ΡŠΠ΅Π΄ΠΈΠ½ΡΠ΅Ρ‚ нСсколько ΠΎΠ±Π΅Ρ‰Π°Π½ΠΈΠΉ Π² ΠΎΠ΄Π½ΠΎ, Ρ€Π΅Π·ΡƒΠ»ΡŒΡ‚Π°Ρ‚ΠΎΠΌ ΠΊΠΎΡ‚ΠΎΡ€ΠΎΠ³ΠΎ являСтся массив Ρ€Π΅Π·ΡƒΠ»ΡŒΡ‚Π°Ρ‚ΠΎΠ² Π΄Ρ€ΡƒΠ³ΠΈΡ… ΠΎΠ±Π΅Ρ‰Π°Π½ΠΈΠΉ.
627 646 /// Если хотябы ΠΎΠ΄Π½ΠΎ ΠΈΠ· ΠΏΠ΅Ρ€Π΅Π΄Π°Π½Π½Ρ‹Ρ… ΠΎΠ±Π΅Ρ‰Π°Π½ΠΈΠΉ Π½Π΅ Π±ΡƒΠ΄Π΅Ρ‚ Π²Ρ‹ΠΏΠΎΠ»Π½Π΅Π½ΠΎ, Ρ‚ΠΎ Π½ΠΎΠ²ΠΎΠ΅ ΠΎΠ±Π΅Ρ‰Π΅Π½ΠΈΠ΅ Ρ‚ΠΎΠΆΠ΅ Π½Π΅ Π±ΡƒΠ΄Π΅Ρ‚ Π²Ρ‹ΠΏΠΎΠ»Π½Π΅Π½ΠΎ.
628 647 /// ΠŸΡ€ΠΈ ΠΎΡ‚ΠΌΠ΅Π½Π΅ Π½ΠΎΠ²ΠΎΠ³ΠΎ обСщания, ΠΏΠ΅Ρ€Π΅Π΄Π°Π½Π½Ρ‹Π΅ обСщания Ρ‚Π°ΠΊΠΆΠ΅ Π±ΡƒΠ΄ΡƒΡ‚ ΠΎΡ‚ΠΌΠ΅Π½Π΅Π½Ρ‹, Ссли Π½ΠΈΠΊΡ‚ΠΎ большС Π½Π° Π½ΠΈΡ… Π½Π΅ подписан.
629 648 /// </summary>
630 649 /// <param name="promises">Бписок ΠΎΠ±Π΅Ρ‰Π°Π½ΠΈΠΉ. Если список пустой, Ρ‚ΠΎ Ρ€Π΅Π·ΡƒΠ»ΡŒΡ‚ΠΈΡ€ΡƒΡŽΡ‰Π΅Π΅ ΠΎΠ±Π΅Ρ‰Π°Π½ΠΈΠ΅ возвращаСтся ΡƒΠΆΠ΅ Π²Ρ‹ΠΏΠΎΠ»Π½Π΅Π½Π½Ρ‹ΠΌ.</param>
631 650 /// <returns>ΠžΠ±Π΅Ρ‰Π°Π½ΠΈΠ΅ ΠΎΠ±ΡŠΠ΅Π΄ΠΈΠ½ΡΡŽΡ‰Π΅Π΅ Π² сСбС Ρ€Π΅Π·ΡƒΠ»ΡŒΡ‚Π°Ρ‚ ΠΏΠ΅Ρ€Π΅Π΄Π°Π½Π½Ρ‹Ρ… ΠΎΠ±Π΅Ρ‰Π°Π½ΠΈΠΉ.</returns>
632 651 /// <exception cref="ArgumentNullException"><paramref name="promises"/> Π½Π΅ ΠΌΠΎΠΆΠ΅Ρ‚ Π±Ρ‹Ρ‚ΡŒ null</exception>
633 652 public static IPromise<T[]> CreateComposite(IList<IPromise<T>> promises) {
634 653 if (promises == null)
635 654 throw new ArgumentNullException();
636 655
637 656 // создаСм аккумулятор для Ρ€Π΅Π·ΡƒΠ»ΡŒΡ‚Π°Ρ‚ΠΎΠ² ΠΈ Ρ€Π΅Π·ΡƒΠ»ΡŒΡ‚ΠΈΡ€ΡƒΡŽΡ‰Π΅Π΅ ΠΎΠ±Π΅Ρ‰Π°Π½ΠΈΠ΅
638 657 var result = new T[promises.Count];
639 658 var promise = new Promise<T[]>();
640 659
641 660 // special case
642 661 if (promises.Count == 0) {
643 662 promise.Resolve(result);
644 663 return promise;
645 664 }
646 665
647 666 int pending = promises.Count;
648 667
649 668 for (int i = 0; i < promises.Count; i++) {
650 669 var dest = i;
651 670
652 671 if (promises[i] != null) {
653 672 promises[i].Then(
654 673 x => {
655 674 result[dest] = x;
656 675 if (Interlocked.Decrement(ref pending) == 0)
657 676 promise.Resolve(result);
658 677 },
659 678 e => {
660 679 promise.Reject(e);
661 680 return default(T);
662 681 }
663 682 );
664 683 } else {
665 684 if (Interlocked.Decrement(ref pending) == 0)
666 685 promise.Resolve(result);
667 686 }
668 687 }
669 688
670 689 promise.Cancelled(
671 690 () => {
672 691 foreach (var d in promises)
673 692 if (d != null && d.IsExclusive)
674 693 d.Cancel();
675 694 }
676 695 );
677 696
678 697 return promise;
679 698 }
680 699
681 700 /// <summary>
682 701 /// ΠžΠ±ΡŠΠ΅Π΄ΠΈΠ½ΡΠ΅Ρ‚ нСсколько ΠΎΠ±Π΅Ρ‰Π°Π½ΠΈΠΉ Π² ΠΎΠ΄Π½ΠΎ. Π Π΅Π·ΡƒΠ»ΡŒΡ‚ΠΈΡ€ΡƒΡŽΡ‰Π΅Π΅ ΠΎΠ±Π΅Ρ‰Π°Π½ΠΈΠ΅ Π±ΡƒΠ΄Π΅Ρ‚ Π²Ρ‹ΠΏΠΎΠ»Π½Π΅Π½ΠΎ ΠΏΡ€ΠΈ
683 702 /// Π²Ρ‹ΠΏΠΎΠ»Π½Π΅Π½ΠΈΠΈ всСх ΡƒΠΊΠ°Π·Π°Π½Π½Ρ‹Ρ… ΠΎΠ±Π΅Ρ‰Π°Π½ΠΈΠΉ. ΠŸΡ€ΠΈ этом Π²ΠΎΠ·Π²Ρ€Π°Ρ‰Π°Π΅ΠΌΡ‹Π΅ значСния ΠΏΠ΅Ρ€Π²ΠΈΡ‡Π½Ρ‹Ρ… ΠΎΠ±Π΅Ρ‰Π°Π½ΠΈΠΉ
684 703 /// ΠΈΠ³Π½ΠΎΡ€ΠΈΡ€ΡƒΡŽΡ‚ΡΡ.
685 704 /// </summary>
686 705 /// <param name="promises">ΠšΠΎΠ»Π»Π΅ΠΊΡ†ΠΈΡ ΠΏΠ΅Ρ€Π²ΠΈΡ‡Π½Ρ‹Ρ… ΠΎΠ±Π΅Ρ‰Π°Π½ΠΈΠΉ, ΠΊΠΎΡ‚ΠΎΡ€Ρ‹Π΅ Π±ΡƒΠ΄ΡƒΡ‚ ΠΎΠ±ΡŠΠ΅Π΄Π΅Π½Π΅Π½Ρ‹ Π² ΠΎΠ΄Π½ΠΎ.</param>
687 706 /// <returns>НовоС ΠΎΠ±Π΅Ρ‰Π°Π½ΠΈΠ΅, ΠΎΠ±ΡŠΠ΅Π΄ΠΈΠ½ΡΡŽΡ‰Π΅Π΅ Π² сСбС ΠΏΠ΅Ρ€Π΅Π΄Π°Π½Π½Ρ‹Π΅.</returns>
688 707 /// <remarks>
689 708 /// Если Π² ΠΊΠΎΠ»Π»Π΅ΠΊΡ†ΠΈΠΈ Π²ΡΡ‚Ρ€Π΅Ρ‡Π°ΡŽΡŒΡΡ <c>null</c>, Ρ‚ΠΎ ΠΎΠ½ΠΈ Π²ΠΎΡΠΏΡ€ΠΈΠ½ΠΈΠΌΠ°ΡŽΡ‚ΡΡ ΠΊΠ°ΠΊ Π²Ρ‹ΠΏΠΎΠ»Π½Π΅Π½Π½Ρ‹Π΅ обСщания.
690 709 /// </remarks>
691 710 public static IPromise CreateComposite(ICollection<IPromise> promises) {
692 711 if (promises == null)
693 712 throw new ArgumentNullException();
694 713 if (promises.Count == 0)
695 714 return Promise<object>.ResultToPromise(null);
696 715
697 716 int countdown = promises.Count;
698 717
699 718 var result = new Promise<object>();
700 719
701 720 foreach (var d in promises) {
702 721 if (d == null) {
703 722 if (Interlocked.Decrement(ref countdown) == 0)
704 723 result.Resolve(null);
705 724 } else {
706 725 d.Then(() => {
707 726 if (Interlocked.Decrement(ref countdown) == 0)
708 727 result.Resolve(null);
709 728 });
710 729 }
711 730 }
712 731
713 732 result.Cancelled(() => {
714 733 foreach (var d in promises)
715 734 if (d != null && d.IsExclusive)
716 735 d.Cancel();
717 736 });
718 737
719 738 return result;
720 739 }
721 740
722 741 public static Promise<T> ResultToPromise(T result) {
723 742 var p = new Promise<T>();
724 743 p.Resolve(result);
725 744 return p;
726 745 }
727 746
728 747 public static Promise<T> ExceptionToPromise(Exception error) {
729 748 if (error == null)
730 749 throw new ArgumentNullException();
731 750
732 751 var p = new Promise<T>();
733 752 p.Reject(error);
734 753 return p;
735 754 }
736 755
737 756 #region IPromiseBase explicit implementation
738 757
758 IPromise IPromise.Then(Action success, ErrorHandler error, Action cancel) {
759 return Then(
760 x => success(),
761 e => {
762 error(e);
763 return default(T);
764 },
765 cancel
766 );
767 }
768
769 IPromise IPromise.Then(Action success, ErrorHandler error) {
770 return Then(
771 x => success(),
772 e => {
773 error(e);
774 return default(T);
775 }
776 );
777 }
778
779 IPromise IPromise.Then(Action success) {
780 return Then(x => success());
781 }
782
783 void IPromise.Last(Action success, ErrorHandler error, Action cancel) {
784 Last(x => success(), error, cancel);
785 }
786
787 void IPromise.Last(Action success, ErrorHandler error) {
788 Last(x => success(), error, null);
789 }
790
791 void IPromise.Last(Action success) {
792 Last(x => success(), null, null);
793 }
794
739 795 IPromise IPromise.Error(ErrorHandler error) {
740 796 return Error(error);
741 797 }
742 798
743 IPromise IPromise.Finally(Action handler) {
744 return Finally(handler);
799 IPromise IPromise.Anyway(Action handler) {
800 return Anyway(handler);
745 801 }
746 802
747 803 IPromise IPromise.Cancelled(Action handler) {
748 804 return Cancelled(handler);
749 805 }
750 806
751 807 void IPromise.Join() {
752 808 Join();
753 809 }
754 810
755 811 void IPromise.Join(int timeout) {
756 812 Join(timeout);
757 813 }
758 814
759 815 #endregion
760 816
761 817
762 818
763 819 }
764 820 }
@@ -1,69 +1,65
1 1 using System.Threading;
2 2 using System;
3 3 #if NET_4_5
4 4 using System.Threading.Tasks;
5 5 #endif
6 6
7 7 namespace Implab {
8 8 public static class PromiseExtensions {
9 9 public static IPromise<T> DispatchToCurrentContext<T>(this IPromise<T> that) {
10 10 Safe.ArgumentNotNull(that, "that");
11 11 var context = SynchronizationContext.Current;
12 12 if (context == null)
13 13 return that;
14 14
15 15 var p = new SyncContextPromise<T>(context, that, true);
16 16
17 that.Then(
18 x => p.Resolve(x),
19 e => {
20 p.Reject(e);
21 return default(T);
22 }
17 that.Last(
18 p.Resolve,
19 p.Reject,
20 p.Cancel
23 21 );
24 22 return p;
25 23 }
26 24
27 25 public static IPromise<T> DispatchToContext<T>(this IPromise<T> that, SynchronizationContext context) {
28 26 Safe.ArgumentNotNull(that, "that");
29 27 Safe.ArgumentNotNull(context, "context");
30 28
31 29 var p = new SyncContextPromise<T>(context, that, true);
32 30
33 that.Then(
34 x => p.Resolve(x),
35 e => {
36 p.Reject(e);
37 return default(T);
38 }
31 that.Last(
32 p.Resolve,
33 p.Reject,
34 p.Cancel
39 35 );
40 36 return p;
41 37 }
42 38
43 39 public static AsyncCallback AsyncCallback<T>(this Promise<T> that, Func<IAsyncResult,T> callback) {
44 40 Safe.ArgumentNotNull(that, "that");
45 41 Safe.ArgumentNotNull(callback, "callback");
46 42 return ar => {
47 43 try {
48 44 that.Resolve(callback(ar));
49 45 } catch (Exception err) {
50 46 that.Reject(err);
51 47 }
52 48 };
53 49 }
54 50
55 51 #if NET_4_5
56 52
57 53 public static Task<T> GetTask<T>(this IPromise<T> that) {
58 54 Safe.ArgumentNotNull(that, "that");
59 55 var tcs = new TaskCompletionSource<T>();
60 56
61 57 that.Last(tcs.SetResult, tcs.SetException, tcs.SetCanceled);
62 58
63 59 return tcs.Task;
64 60 }
65 61
66 62 #endif
67 63 }
68 64 }
69 65
@@ -1,27 +1,27
1 1 using System.Reflection;
2 2 using System.Runtime.CompilerServices;
3 3 using System.Runtime.InteropServices;
4 4
5 5 // Information about this assembly is defined by the following attributes.
6 6 // Change them to the values specific to your project.
7 7
8 8 [assembly: AssemblyTitle("Implab")]
9 9 [assembly: AssemblyDescription("Tools")]
10 10 [assembly: AssemblyConfiguration("")]
11 11 [assembly: AssemblyCompany("")]
12 12 [assembly: AssemblyProduct("")]
13 13 [assembly: AssemblyCopyright("Implab")]
14 14 [assembly: AssemblyTrademark("")]
15 15 // The assembly version has the format "{Major}.{Minor}.{Build}.{Revision}".
16 16 // The form "{Major}.{Minor}.*" will automatically update the build and revision,
17 17 // and "{Major}.{Minor}.{Build}.*" will update just the revision.
18 18
19 [assembly: AssemblyVersion("1.0.*")]
19 [assembly: AssemblyVersion("2.0.*")]
20 20 [assembly: ComVisible(false)]
21 21
22 22 // The following attributes are used to specify the signing key for the assembly,
23 23 // if desired. See the Mono documentation for more information about signing.
24 24
25 25 //[assembly: AssemblyDelaySign(false)]
26 26 //[assembly: AssemblyKeyFile("")]
27 27
@@ -1,140 +1,136
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
8 8 {
9 9 /// <summary>
10 10 /// This class allows to interact with asyncronuos task.
11 11 /// </summary>
12 12 /// <remarks>
13 13 /// Members of this object are thread safe.
14 14 /// </remarks>
15 15 public class TaskController: IProgressNotifier, ITaskController
16 16 {
17 17 readonly object m_lock;
18 18 string m_message;
19 19
20 20 float m_current;
21 21 float m_max;
22 22
23 23 bool m_cancelled;
24 24
25 25 public event EventHandler Cancelled;
26 26 public event EventHandler<ValueEventArgs<string>> MessageUpdated;
27 27 public event EventHandler<ValueEventArgs<float>> ProgressUpdated;
28 28 public event EventHandler<ProgressInitEventArgs> ProgressInit;
29 29
30 30 public TaskController()
31 31 {
32 32 m_lock = new Object();
33 33 }
34 34
35 35 public string Message
36 36 {
37 37 get
38 38 {
39 39 lock (m_lock)
40 40 return m_message;
41 41 }
42 42 set
43 43 {
44 44 lock (m_lock)
45 45 {
46 46 m_message = value;
47 47 OnMessageUpdated();
48 48 }
49 49 }
50 50 }
51 51
52 52 public float CurrentProgress
53 53 {
54 54 get
55 55 {
56 56 lock (m_lock)
57 57 return m_current;
58 58 }
59 59 set
60 60 {
61 61 lock (m_lock)
62 62 {
63 63 var prev = m_current;
64 64 m_current = value;
65 65 if (m_current >= m_max)
66 66 m_current = m_max;
67 67 if (m_current != prev)
68 68 OnProgressUpdated();
69 69 }
70 70 }
71 71 }
72 72
73 73 public void InitProgress(float current, float max, string message)
74 74 {
75 75 if (max < 0)
76 76 throw new ArgumentOutOfRangeException("max");
77 77 if (current < 0 || current > max)
78 78 throw new ArgumentOutOfRangeException("current");
79 79
80 80 lock(m_lock) {
81 81 m_current = current;
82 82 m_max = max;
83 83 m_message = message;
84 84 OnProgressInit();
85 85 }
86 86 }
87 87
88 88 public bool IsCancelled {
89 89 get {
90 90 lock (m_lock)
91 91 return m_cancelled;
92 92 }
93 93 }
94 94
95 public bool Cancel() {
95 public void Cancel() {
96 96 lock (m_lock) {
97 if (!m_cancelled) {
97 if (!m_cancelled)
98 98 m_cancelled = true;
99 return true;
100 } else {
101 return false;
102 }
103 99 }
104 100 }
105 101
106 102 protected virtual void OnCancelled() {
107 103 var temp = Cancelled;
108 104 if (temp != null) {
109 105 temp(this,new EventArgs());
110 106 }
111 107 }
112 108
113 109 protected virtual void OnMessageUpdated()
114 110 {
115 111 var temp = MessageUpdated;
116 112 if (temp != null)
117 113 {
118 114 temp(this, new ValueEventArgs<string>(m_message));
119 115 }
120 116 }
121 117
122 118 protected virtual void OnProgressUpdated()
123 119 {
124 120 var temp = ProgressUpdated;
125 121 if (temp != null)
126 122 {
127 123 temp(this,new ValueEventArgs<float>(m_current));
128 124 }
129 125 }
130 126
131 127 protected virtual void OnProgressInit()
132 128 {
133 129 var temp = ProgressInit;
134 130 if (temp != null)
135 131 {
136 132 temp(this, new ProgressInitEventArgs(m_current,m_max, m_message));
137 133 }
138 134 }
139 135 }
140 136 }
General Comments 0
You need to be logged in to leave comments. Login now