##// END OF EJS Templates
removed the reference to the parent from the promise object this allows...
cin -
r33:b255e4aeef17 default
parent child
Show More
@@ -328,6 +328,59 namespace Implab.Test {
328 328 Assert.IsTrue(flags[1]);
329 329 Assert.IsTrue(flags[2]);
330 330 }
331
332 [TestMethod]
333 public void ChainedCancel1Test() {
334 // ΠΏΡ€ΠΈ ΠΎΡ‚ΠΌΠ΅Π½Π΅ сцСплСнной асинхронной ΠΎΠΏΠ΅Ρ€Π°Ρ†ΠΈΠΈ всС ΠΎΠ±Π΅Ρ‰Π°Π½ΠΈΠ΅ Π΄ΠΎΠ»ΠΆΠ½ΠΎ
335 // Π·Π°Π²Π΅Ρ€ΡˆΠ°Ρ‚ΡŒΡΡ ошибкой OperationCanceledException
336 var p = PromiseHelper
337 .Sleep(1, "Hi, HAL!")
338 .Chain(x => {
339 // запускаСм Π΄Π²Π΅ асинхронныС ΠΎΠΏΠ΅Ρ€Π°Ρ†ΠΈΠΈ
340 var result = PromiseHelper.Sleep(1000, "HEM ENABLED!!!");
341 // вторая опСрация отмСняСт ΠΏΠ΅Ρ€Π²ΡƒΡŽ Π΄ΠΎ Π·Π°Π²Π΅Ρ€ΡˆΠ΅Π½ΠΈΡ
342 PromiseHelper
343 .Sleep(100, "HAL, STOP!")
344 .Then(() => result.Cancel());
345 return result;
346 });
347 try {
348 p.Join();
349 } catch (TargetInvocationException err) {
350 Assert.IsTrue(err.InnerException is OperationCanceledException);
351 }
352 }
353
354 [TestMethod]
355 public void ChainedCancel2Test() {
356 // ΠΏΡ€ΠΈ ΠΎΡ‚ΠΌΠ΅Π½Π΅ Ρ†Π΅ΠΏΠΎΡ‡ΠΊΠΈ ΠΎΠ±Π΅Ρ‰Π°Π½ΠΈΠΉ, Π²Π»ΠΎΠΆΠ΅Π½Π½Ρ‹Π΅ ΠΎΠΏΠ΅Ρ€Π°Ρ†ΠΈΠΈ Ρ‚Π°ΠΊΠΆΠ΅ Π΄ΠΎΠ»ΠΆΠ½Ρ‹ ΠΎΡ‚ΠΌΠ΅Π½ΡΡ‚ΡŒΡΡ
357 IPromiseBase p = null;
358 var pSurvive = new Promise<bool>();
359 var hemStarted = new ManualResetEvent(false);
360 p = PromiseHelper
361 .Sleep(1, "Hi, HAL!")
362 .Chain(x => {
363 hemStarted.Set();
364 // запускаСм Π΄Π²Π΅ асинхронныС ΠΎΠΏΠ΅Ρ€Π°Ρ†ΠΈΠΈ
365 var result = PromiseHelper
366 .Sleep(1000, "HEM ENABLED!!!")
367 .Then(s => pSurvive.Resolve(false));
368
369 result
370 .Cancelled(() => pSurvive.Resolve(true));
371
372 return result;
373 });
374
375 hemStarted.WaitOne();
376 p.Cancel();
377
378 try {
379 p.Join();
380 } catch (OperationCanceledException) {
381 Assert.IsTrue(pSurvive.Join());
382 }
383 }
331 384 }
332 385 }
333 386
1 NO CONTENT: modified file, binary diff hidden
@@ -8,14 +8,13 namespace Implab
8 8 public interface IPromise<T>: IPromiseBase
9 9 {
10 10
11 T Join();
12
13 T Join(int timeout);
11 new T Join();
12 new T Join(int timeout);
14 13
15 14 IPromise<T> Then(ResultHandler<T> success, ErrorHandler error);
16 15 IPromise<T> Then(ResultHandler<T> success, ErrorHandler<T> error);
17 16 IPromise<T> Then(ResultHandler<T> success);
18 IPromise<T> Error(ErrorHandler error);
17 new IPromise<T> Error(ErrorHandler error);
19 18 IPromise<T> Error(ErrorHandler<T> error);
20 19
21 20 IPromise<T2> Map<T2>(ResultMapper<T,T2> mapper, ErrorHandler error);
@@ -24,9 +23,9 namespace Implab
24 23 IPromise<T2> Chain<T2>(ChainedOperation<T, T2> chained, ErrorHandler error);
25 24 IPromise<T2> Chain<T2>(ChainedOperation<T, T2> chained);
26 25
27 IPromise<T> Cancelled(Action handler);
28 IPromise<T> Finally(Action handler);
29 IPromise<T> Anyway(Action handler);
26 new IPromise<T> Cancelled(Action handler);
27 new IPromise<T> Finally(Action handler);
28 new IPromise<T> Anyway(Action handler);
30 29
31 30 }
32 31 }
@@ -23,8 +23,15 namespace Implab {
23 23
24 24 IPromiseBase Then(Action success,ErrorHandler error);
25 25 IPromiseBase Then(Action success);
26 IPromiseBase Error(ErrorHandler error);
27 IPromiseBase Anyway(Action handler);
28 IPromiseBase Finally(Action handler);
29 IPromiseBase Cancelled(Action handler);
26 30
27 31 IPromise<T> Cast<T>();
28 32
33 void Join();
34 void Join(int timeout);
35
29 36 }
30 37 }
@@ -11,7 +11,7 namespace Implab {
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);
14 public delegate IPromise<TNew> ChainedOperation<in TSrc, TNew>(TSrc result);
15 15
16 16 /// <summary>
17 17 /// Класс для асинхронного получСния Ρ€Π΅Π·ΡƒΠ»ΡŒΡ‚Π°Ρ‚ΠΎΠ². Π’Π°ΠΊ Π½Π°Π·Ρ‹Π²Π°Π΅ΠΌΠΎΠ΅ "ΠΎΠ±Π΅Ρ‰Π°Π½ΠΈΠ΅".
@@ -86,7 +86,6 namespace Implab {
86 86 const int RejectedState = 3;
87 87 const int CancelledState = 4;
88 88
89 readonly IPromiseBase m_parent;
90 89 readonly bool m_cancellable;
91 90
92 91 int m_childrenCount = 0;
@@ -102,12 +101,15 namespace Implab {
102 101
103 102 public Promise(IPromiseBase parent, bool cancellable) {
104 103 m_cancellable = cancellable;
105 m_parent = parent;
106 }
107
108 void InternalCancel() {
109 // don't try to cancel parent :)
110 Cancel(false);
104 if (parent != null)
105 AddHandler(
106 null,
107 null,
108 () => {
109 if (parent.IsExclusive)
110 parent.Cancel();
111 }
112 );
111 113 }
112 114
113 115 bool BeginTransit() {
@@ -159,6 +161,16 namespace Implab {
159 161 }
160 162
161 163 /// <summary>
164 /// ВыполняСт ΠΎΠ±Π΅Ρ‰Π°Π½ΠΈΠ΅, сообщая ΠΎΠ± ΡƒΡΠΏΠ΅ΡˆΠ½ΠΎΠΌ Π²Ρ‹ΠΏΠΎΠ»Π½Π΅Π½ΠΈΠΈ. Π Π΅Π·ΡƒΠ»ΡŒΡ‚Π°Ρ‚ΠΎΠΌ выполнСния Π±ΡƒΠ΄Π΅Ρ‚ пустоС значСния.
165 /// </summary>
166 /// <remarks>
167 /// Π”Π°Π½Π½Ρ‹ΠΉ Π²Π°Ρ€ΠΈΠ°Π½Ρ‚ ΡƒΠ΄ΠΎΠ±Π΅Π½ Π² случаях, ΠΊΠΎΠ³Π΄Π° интСрСсСн Ρ„Π°ΠΊΡ‚ выполнСния ΠΎΠΏΠ΅Ρ€Π°Ρ†ΠΈΠΈ, Π½Π΅ΠΆΠ΅Π»ΠΈ ΠΏΠΎΠ»ΡƒΡ‡Π΅Π½Π½ΠΎΠ΅ Π·Π½Π°Ρ‡Π΅Π½ΠΈΠ΅.
168 /// </remarks>
169 public void Resolve() {
170 Resolve(default(T));
171 }
172
173 /// <summary>
162 174 /// ВыполняСт ΠΎΠ±Π΅Ρ‰Π°Π½ΠΈΠ΅, сообщая ΠΎΠ± ошибкС
163 175 /// </summary>
164 176 /// <remarks>
@@ -185,7 +197,18 namespace Implab {
185 197 /// </summary>
186 198 /// <returns><c>true</c> ΠžΠΏΠ΅Ρ€Π°Ρ†ΠΈΡ Π±Ρ‹Π»Π° ΠΎΡ‚ΠΌΠ΅Π½Π΅Π½Π°, ΠΎΠ±Ρ€Π°Π±ΠΎΡ‚Ρ‡ΠΈΠΊΠΈ Π½Π΅ Π±ΡƒΠ΄ΡƒΡ‚ Π²Ρ‹Π·Π²Π°Π½Ρ‹.<c>false</c> ΠΎΡ‚ΠΌΠ΅Π½Π° Π½Π΅ Π²ΠΎΠ·ΠΌΠΎΠΆΠ½Π°, ΠΏΠΎΡΠΊΠΎΠ»ΡŒΠΊΡƒ ΠΎΠ±Π΅Ρ‰Π°Π½ΠΈΠ΅ ΡƒΠΆΠ΅ Π²Ρ‹ΠΏΠΎΠ»Π½Π΅Π½ΠΎ ΠΈ ΠΎΠ±Ρ€Π°Π±ΠΎΡ‚Ρ‡ΠΈΠΊΠΈ ΠΎΡ‚Ρ€Π°Π±ΠΎΡ‚Π°Π»ΠΈ.</returns>
187 199 public bool Cancel() {
188 return Cancel(true);
200 if (BeginTransit()) {
201 CompleteTransit(CancelledState);
202 OnStateChanged();
203 return true;
204 } else {
205 return false;
206 }
207 }
208
209 // сдСлано для Π²ΠΎΠ·Π²Ρ€Π°Ρ‰Π°Π΅ΠΌΠΎΠ³ΠΎ Ρ‚ΠΈΠΏΠ° void
210 protected void InternalCancel() {
211 Cancel();
189 212 }
190 213
191 214 /// <summary>
@@ -229,13 +252,11 namespace Implab {
229 252 return medium;
230 253 }
231 254
232 public IPromiseBase Then(Action success,ErrorHandler error)
233 {
255 public IPromiseBase Then(Action success, ErrorHandler error) {
234 256 return Then(x => success(), error);
235 257 }
236 258
237 public IPromiseBase Then(Action success)
238 {
259 public IPromiseBase Then(Action success) {
239 260 return Then(x => success());
240 261 }
241 262
@@ -267,7 +288,7 namespace Implab {
267 288 errorHandler = x => {
268 289 try {
269 290 medium.Resolve(error(x));
270 } catch(Exception e) {
291 } catch (Exception e) {
271 292 medium.Reject(e);
272 293 }
273 294 };
@@ -338,7 +359,7 namespace Implab {
338 359 if (handler == null)
339 360 return this;
340 361
341 var medium = new Promise<T>();
362 var medium = new Promise<T>(this,true);
342 363
343 364 AddHandler(
344 365 x => {
@@ -377,7 +398,7 namespace Implab {
377 398 throw new ArgumentNullException("mapper");
378 399
379 400 // создаСм ΠΏΡ€ΠΈΡ†Π΅ΠΏΠ»Π΅Π½Π½ΠΎΠ΅ ΠΎΠ±Π΅Ρ‰Π°Π½ΠΈΠ΅
380 var chained = new Promise<TNew>();
401 var chained = new Promise<TNew>(this,true);
381 402
382 403 ResultHandler<T> resultHandler = result => chained.Resolve(mapper(result));
383 404 ErrorHandler errorHandler = delegate(Exception e) {
@@ -427,12 +448,21 namespace Implab {
427 448
428 449 var promise = chained(result);
429 450
430 // notify chained operation that it's not needed
431 medium.Cancelled(() => promise.Cancel());
432 451 promise.Then(
433 452 x => medium.Resolve(x),
434 453 e => medium.Reject(e)
435 454 );
455
456 // notify chained operation that it's not needed anymore
457 // порядок Π²Ρ‹Π·ΠΎΠ²Π° Then, Cancelled Π²Π°ΠΆΠ΅Π½, ΠΏΠΎΡΠΊΠΎΠ»ΡŒΠΊΡƒ ΠΎΡ‚ этого
458 // зависит IsExclusive
459 medium.Cancelled(() => {
460 if(promise.IsExclusive)
461 promise.Cancel();
462 });
463
464 // внСшняя ΠΎΡ‚ΠΌΠ΅Π½Π° связанной ΠΎΠΏΠ΅Ρ€Π°Ρ†ΠΈΠΈ рассматриваСтся ΠΊΠ°ΠΊ ошибка
465 promise.Cancelled(() => medium.Reject(new OperationCanceledException()));
436 466 };
437 467
438 468 ErrorHandler errorHandler = delegate(Exception e) {
@@ -531,7 +561,8 namespace Implab {
531 561 }
532 562
533 563 void AddHandler(ResultHandler<T> success, ErrorHandler error, Action cancel) {
534 Interlocked.Increment(ref m_childrenCount);
564 if (success != null || error != null)
565 Interlocked.Increment(ref m_childrenCount);
535 566
536 567 HandlerDescriptor handler = new HandlerDescriptor {
537 568 resultHandler = success,
@@ -588,20 +619,6 namespace Implab {
588 619 }
589 620 }
590 621
591 protected bool Cancel(bool dependencies) {
592 if (BeginTransit()) {
593 CompleteTransit(CancelledState);
594 OnStateChanged();
595
596 if (dependencies && m_parent != null && m_parent.IsExclusive)
597 m_parent.Cancel();
598
599 return true;
600 } else {
601 return false;
602 }
603 }
604
605 622 /// <summary>
606 623 /// ΠžΠ±ΡŠΠ΅Π΄ΠΈΠ½ΡΠ΅Ρ‚ нСсколько ΠΎΠ±Π΅Ρ‰Π°Π½ΠΈΠΉ Π² ΠΎΠ΄Π½ΠΎ, Ρ€Π΅Π·ΡƒΠ»ΡŒΡ‚Π°Ρ‚ΠΎΠΌ ΠΊΠΎΡ‚ΠΎΡ€ΠΎΠ³ΠΎ являСтся массив Ρ€Π΅Π·ΡƒΠ»ΡŒΡ‚Π°Ρ‚ΠΎΠ² Π΄Ρ€ΡƒΠ³ΠΈΡ… ΠΎΠ±Π΅Ρ‰Π°Π½ΠΈΠΉ.
607 624 /// Если хотябы ΠΎΠ΄Π½ΠΎ ΠΈΠ· ΠΏΠ΅Ρ€Π΅Π΄Π°Π½Π½Ρ‹Ρ… ΠΎΠ±Π΅Ρ‰Π°Π½ΠΈΠΉ Π½Π΅ Π±ΡƒΠ΄Π΅Ρ‚ Π²Ρ‹ΠΏΠΎΠ»Π½Π΅Π½ΠΎ, Ρ‚ΠΎ Π½ΠΎΠ²ΠΎΠ΅ ΠΎΠ±Π΅Ρ‰Π΅Π½ΠΈΠ΅ Ρ‚ΠΎΠΆΠ΅ Π½Π΅ Π±ΡƒΠ΄Π΅Ρ‚ Π²Ρ‹ΠΏΠΎΠ»Π½Π΅Π½ΠΎ.
@@ -629,20 +646,25 namespace Implab {
629 646 for (int i = 0; i < promises.Count; i++) {
630 647 var dest = i;
631 648
632 promises[i].Then(
633 x => {
634 result[dest] = x;
635 if(Interlocked.Decrement(ref pending) == 0)
636 promise.Resolve(result);
637 },
638 e => promise.Reject(e)
639 );
649 if (promises[i] != null) {
650 promises[i].Then(
651 x => {
652 result[dest] = x;
653 if (Interlocked.Decrement(ref pending) == 0)
654 promise.Resolve(result);
655 },
656 e => promise.Reject(e)
657 );
658 } else {
659 if (Interlocked.Decrement(ref pending) == 0)
660 promise.Resolve(result);
661 }
640 662 }
641 663
642 664 promise.Cancelled(
643 665 () => {
644 foreach(var d in promises)
645 if(d.IsExclusive)
666 foreach (var d in promises)
667 if (d != null && d.IsExclusive)
646 668 d.Cancel();
647 669 }
648 670 );
@@ -650,6 +672,47 namespace Implab {
650 672 return promise;
651 673 }
652 674
675 /// <summary>
676 /// ΠžΠ±ΡŠΠ΅Π΄ΠΈΠ½ΡΠ΅Ρ‚ нСсколько ΠΎΠ±Π΅Ρ‰Π°Π½ΠΈΠΉ Π² ΠΎΠ΄Π½ΠΎ. Π Π΅Π·ΡƒΠ»ΡŒΡ‚ΠΈΡ€ΡƒΡŽΡ‰Π΅Π΅ ΠΎΠ±Π΅Ρ‰Π°Π½ΠΈΠ΅ Π±ΡƒΠ΄Π΅Ρ‚ Π²Ρ‹ΠΏΠΎΠ»Π½Π΅Π½ΠΎ ΠΏΡ€ΠΈ
677 /// Π²Ρ‹ΠΏΠΎΠ»Π½Π΅Π½ΠΈΠΈ всСх ΡƒΠΊΠ°Π·Π°Π½Π½Ρ‹Ρ… ΠΎΠ±Π΅Ρ‰Π°Π½ΠΈΠΉ. ΠŸΡ€ΠΈ этом Π²ΠΎΠ·Π²Ρ€Π°Ρ‰Π°Π΅ΠΌΡ‹Π΅ значСния ΠΏΠ΅Ρ€Π²ΠΈΡ‡Π½Ρ‹Ρ… ΠΎΠ±Π΅Ρ‰Π°Π½ΠΈΠΉ
678 /// ΠΈΠ³Π½ΠΎΡ€ΠΈΡ€ΡƒΡŽΡ‚ΡΡ.
679 /// </summary>
680 /// <param name="promises">ΠšΠΎΠ»Π»Π΅ΠΊΡ†ΠΈΡ ΠΏΠ΅Ρ€Π²ΠΈΡ‡Π½Ρ‹Ρ… ΠΎΠ±Π΅Ρ‰Π°Π½ΠΈΠΉ, ΠΊΠΎΡ‚ΠΎΡ€Ρ‹Π΅ Π±ΡƒΠ΄ΡƒΡ‚ ΠΎΠ±ΡŠΠ΅Π΄Π΅Π½Π΅Π½Ρ‹ Π² ΠΎΠ΄Π½ΠΎ.</param>
681 /// <returns>НовоС ΠΎΠ±Π΅Ρ‰Π°Π½ΠΈΠ΅, ΠΎΠ±ΡŠΠ΅Π΄ΠΈΠ½ΡΡŽΡ‰Π΅Π΅ Π² сСбС ΠΏΠ΅Ρ€Π΅Π΄Π°Π½Π½Ρ‹Π΅.</returns>
682 /// <remarks>
683 /// Если Π² ΠΊΠΎΠ»Π»Π΅ΠΊΡ†ΠΈΠΈ Π²ΡΡ‚Ρ€Π΅Ρ‡Π°ΡŽΡŒΡΡ <c>null</c>, Ρ‚ΠΎ ΠΎΠ½ΠΈ Π²ΠΎΡΠΏΡ€ΠΈΠ½ΠΈΠΌΠ°ΡŽΡ‚ΡΡ ΠΊΠ°ΠΊ Π²Ρ‹ΠΏΠΎΠ»Π½Π΅Π½Π½Ρ‹Π΅ обСщания.
684 /// </remarks>
685 public static IPromiseBase CreateComposite(ICollection<IPromiseBase> promises) {
686 if (promises == null)
687 throw new ArgumentNullException();
688 if (promises.Count == 0)
689 return Promise<object>.ResultToPromise(null);
690
691 int countdown = promises.Count;
692
693 var result = new Promise<object>();
694
695 foreach (var d in promises) {
696 if (d == null) {
697 if (Interlocked.Decrement(ref countdown) == 0)
698 result.Resolve(null);
699 } else {
700 d.Then(() => {
701 if (Interlocked.Decrement(ref countdown) == 0)
702 result.Resolve(null);
703 });
704 }
705 }
706
707 result.Cancelled(() => {
708 foreach (var d in promises)
709 if (d != null && d.IsExclusive)
710 d.Cancel();
711 });
712
713 return result;
714 }
715
653 716 public static Promise<T> ResultToPromise(T result) {
654 717 var p = new Promise<T>();
655 718 p.Resolve(result);
@@ -665,5 +728,35 namespace Implab {
665 728 return p;
666 729 }
667 730
731 #region IPromiseBase explicit implementation
732
733 IPromiseBase IPromiseBase.Error(ErrorHandler error) {
734 return Error(error);
735 }
736
737 IPromiseBase IPromiseBase.Anyway(Action handler) {
738 return Anyway(handler);
739 }
740
741 IPromiseBase IPromiseBase.Finally(Action handler) {
742 return Finally(handler);
743 }
744
745 IPromiseBase IPromiseBase.Cancelled(Action handler) {
746 return Cancelled(handler);
747 }
748
749 void IPromiseBase.Join() {
750 Join();
751 }
752
753 void IPromiseBase.Join(int timeout) {
754 Join(timeout);
755 }
756
757 #endregion
758
759
760
668 761 }
669 762 }
General Comments 0
You need to be logged in to leave comments. Login now