##// END OF EJS Templates
promises refactoring
cin -
r106:d4e38929ce36 v2
parent child
Show More
@@ -0,0 +1,135
1 using System;
2 using System.Collections.Generic;
3 using System.Threading;
4 using System.Collections;
5
6 namespace Implab.Parallels {
7 public class MTCustomQueue<TNode> : IEnumerable<TNode> where TNode : MTCustomQueueNode<TNode> {
8 TNode m_first;
9 TNode m_last;
10
11 public void Enqueue(TNode next) {
12 Thread.MemoryBarrier();
13
14 var last = m_last;
15
16 // Interlocaked.CompareExchange implies Thread.MemoryBarrier();
17 // to ensure that the next node is completely constructed
18 while (last != Interlocked.CompareExchange(ref m_last, next, last))
19 last = m_last;
20
21 if (last != null)
22 last.next = next;
23 else
24 m_first = next;
25 }
26
27 public bool TryDequeue(out TNode node) {
28 TNode first;
29 TNode next;
30 node = null;
31
32 Thread.MemoryBarrier();
33 do {
34 first = m_first;
35 if (first == null)
36 return false;
37 next = first.next;
38 if (next == null) {
39 // this is the last element,
40 // then try to update the tail
41 if (first != Interlocked.CompareExchange(ref m_last, null, first)) {
42 // this is the race condition
43 if (m_last == null)
44 // the queue is empty
45 return false;
46 // tail has been changed, we need to restart
47 continue;
48 }
49
50 // tail succesfully updated and first.next will never be changed
51 // other readers will fail due to inconsistency m_last != m_fist && m_first.next == null
52 // however the parallel writer may update the m_first since the m_last is null
53
54 // so we need to fix inconsistency by setting m_first to null or if it has been
55 // updated by the writer already then we should just to give up
56 Interlocked.CompareExchange(ref m_first, null, first);
57 break;
58
59 }
60 if (first == Interlocked.CompareExchange(ref m_first, next, first))
61 // head succesfully updated
62 break;
63 } while (true);
64
65 node = first;
66 return true;
67 }
68
69 #region IEnumerable implementation
70
71 class Enumerator : IEnumerator<TNode> {
72 TNode m_current;
73 TNode m_first;
74
75 public Enumerator(TNode first) {
76 m_first = first;
77 }
78
79 #region IEnumerator implementation
80
81 public bool MoveNext() {
82 m_current = m_current == null ? m_first : m_current.next;
83 return m_current != null;
84 }
85
86 public void Reset() {
87 m_current = null;
88 }
89
90 object IEnumerator.Current {
91 get {
92 if (m_current == null)
93 throw new InvalidOperationException();
94 return m_current;
95 }
96 }
97
98 #endregion
99
100 #region IDisposable implementation
101
102 public void Dispose() {
103 }
104
105 #endregion
106
107 #region IEnumerator implementation
108
109 public TNode Current {
110 get {
111 if (m_current == null)
112 throw new InvalidOperationException();
113 return m_current;
114 }
115 }
116
117 #endregion
118 }
119
120 public IEnumerator<TNode> GetEnumerator() {
121 return new Enumerator(m_first);
122 }
123
124 #endregion
125
126 #region IEnumerable implementation
127
128 IEnumerator IEnumerable.GetEnumerator() {
129 return GetEnumerator();
130 }
131
132 #endregion
133 }
134 }
135
@@ -0,0 +1,6
1 namespace Implab.Parallels {
2 public class MTCustomQueueNode<TNode> where TNode : MTCustomQueueNode<TNode> {
3 public TNode next;
4 }
5 }
6
@@ -42,7 +42,13 namespace Implab.Fx
42 {
42 {
43 var anim = ctl.AnimateTransparency(0);
43 var anim = ctl.AnimateTransparency(0);
44
44
45 return anim.Play().DispatchToControl(ctl).Then(frm => frm.Close());
45 return anim
46 .Play()
47 .DispatchToControl(ctl)
48 .Then(frm => {
49 frm.Close();
50 return frm;
51 });
46 }
52 }
47
53
48 public static IPromise<T> OverlayFadeIn<T>(this Form that, T overlay) where T : Form
54 public static IPromise<T> OverlayFadeIn<T>(this Form that, T overlay) where T : Form
@@ -19,9 +19,9 namespace Implab.Fx {
19 m_target = target;
19 m_target = target;
20 }
20 }
21
21
22 protected override void InvokeHandler(HandlerDescriptor handler) {
22 protected override void InvokeHandler(AbstractHandler handler) {
23 if (m_target.InvokeRequired)
23 if (m_target.InvokeRequired)
24 m_target.BeginInvoke(new Action<HandlerDescriptor>(base.InvokeHandler), handler);
24 m_target.BeginInvoke(new Action<AbstractHandler>(base.InvokeHandler), handler);
25 else
25 else
26 base.InvokeHandler(handler);
26 base.InvokeHandler(handler);
27 }
27 }
@@ -426,8 +426,11 namespace Implab.Test {
426 hemStarted.Set();
426 hemStarted.Set();
427 // запускаем две асинхронные операции
427 // запускаем две асинхронные операции
428 var result = PromiseHelper
428 var result = PromiseHelper
429 .Sleep(10000, "HEM ENABLED!!!")
429 .Sleep(100000000, "HEM ENABLED!!!")
430 .Then(s => pSurvive.Resolve(false));
430 .Then(s => {
431 pSurvive.Resolve(false);
432 return s;
433 });
431
434
432 result
435 result
433 .Cancelled(() => pSurvive.Resolve(true));
436 .Cancelled(() => pSurvive.Resolve(true));
@@ -13,12 +13,6 namespace Implab {
13
13
14 void On(Action<T> success);
14 void On(Action<T> success);
15
15
16 IPromise<T> Then(Action<T> success, Func<Exception,T> error, Action cancel);
17
18 IPromise<T> Then(Action<T> success, Func<Exception,T> error);
19
20 IPromise<T> Then(Action<T> success);
21
22 IPromise<T2> Then<T2>(Func<T, T2> mapper, Func<Exception,T2> error, Action cancel);
16 IPromise<T2> Then<T2>(Func<T, T2> mapper, Func<Exception,T2> error, Action cancel);
23
17
24 IPromise<T2> Then<T2>(Func<T, T2> mapper, Func<Exception,T2> error);
18 IPromise<T2> Then<T2>(Func<T, T2> mapper, Func<Exception,T2> error);
@@ -148,6 +148,8
148 <Compile Include="IComponentContainer.cs" />
148 <Compile Include="IComponentContainer.cs" />
149 <Compile Include="MTComponentContainer.cs" />
149 <Compile Include="MTComponentContainer.cs" />
150 <Compile Include="PromiseEventType.cs" />
150 <Compile Include="PromiseEventType.cs" />
151 <Compile Include="Parallels\MTCustomQueue.cs" />
152 <Compile Include="Parallels\MTCustomQueueNode.cs" />
151 </ItemGroup>
153 </ItemGroup>
152 <Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
154 <Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
153 <ItemGroup />
155 <ItemGroup />
@@ -42,53 +42,68 namespace Implab {
42 /// </remarks>
42 /// </remarks>
43 public class Promise<T> : IPromise<T> {
43 public class Promise<T> : IPromise<T> {
44
44
45 protected struct HandlerDescriptor {
45 protected abstract class AbstractHandler : MTCustomQueueNode<AbstractHandler> {
46 public Action<T> resultHandler;
46 public abstract void Resolve(T result);
47 public Func<Exception,T> errorHandler;
47 public abstract void Reject(Exception error);
48 public Action cancellHandler;
48 public abstract void Cancel();
49 public Promise<T> medium;
49 }
50
51 protected class HandlerDescriptor<T2> : AbstractHandler {
52
53 readonly Func<T,T2> m_resultHandler;
54 readonly Func<Exception,T2> m_errorHandler;
55 readonly Action m_cancellHandler;
56 readonly Promise<T2> m_medium;
50
57
51 public void Resolve(T result) {
58 public HandlerDescriptor(Func<T,T2> resultHandler, Func<Exception,T2> errorHandler, Action cancelHandler, Promise<T2> medium) {
52 if (resultHandler != null) {
59 m_resultHandler = resultHandler;
60 m_errorHandler = errorHandler;
61 m_cancellHandler = cancelHandler;
62 m_medium = medium;
63 }
64
65 public override void Resolve(T result) {
66 if (m_resultHandler != null) {
53 try {
67 try {
54 resultHandler(result);
68 if (m_medium != null)
69 m_medium.Resolve(m_resultHandler(result));
70 else
71 m_resultHandler(result);
55 } catch (Exception e) {
72 } catch (Exception e) {
56 Reject(e);
73 Reject(e);
57 return;
58 }
74 }
59 }
75 } else if(m_medium != null)
60 if (medium != null)
76 m_medium.Resolve(default(T2));
61 medium.Resolve(result);
62 }
77 }
63
78
64 public void Reject(Exception err) {
79 public override void Reject(Exception error) {
65 if (errorHandler != null) {
80 if (m_errorHandler != null) {
66 try {
81 try {
67 var res = errorHandler(err);
82 var res = m_errorHandler(error);
68 if (medium != null)
83 if (m_medium != null)
69 medium.Resolve(res);
84 m_medium.Resolve(res);
70 /*} catch (TransientPromiseException err2) {
85 /*} catch (TransientPromiseException err2) {
71 if (medium != null)
86 if (medium != null)
72 medium.Reject(err2.InnerException);*/
87 medium.Reject(err2.InnerException);*/
73 } catch (Exception err2) {
88 } catch (Exception err2) {
74 if (medium != null)
89 if (m_medium != null)
75 medium.Reject(err2);
90 m_medium.Reject(err2);
76 }
91 }
77 } else if (medium != null)
92 } else if (m_medium != null)
78 medium.Reject(err);
93 m_medium.Reject(error);
79 }
94 }
80
95
81 public void Cancel() {
96 public override void Cancel() {
82 if (cancellHandler != null) {
97 if (m_cancellHandler != null) {
83 try {
98 try {
84 cancellHandler();
99 m_cancellHandler();
85 } catch (Exception err) {
100 } catch (Exception err) {
86 Reject(err);
101 Reject(err);
87 return;
102 return;
88 }
103 }
89 }
104 }
90 if (medium != null)
105 if (m_medium != null)
91 medium.Cancel();
106 m_medium.Cancel();
92 }
107 }
93 }
108 }
94
109
@@ -103,14 +118,15 namespace Implab {
103 T m_result;
118 T m_result;
104 Exception m_error;
119 Exception m_error;
105
120
106 readonly MTQueue<HandlerDescriptor> m_handlers = new MTQueue<HandlerDescriptor>();
121 readonly MTCustomQueue<AbstractHandler> m_handlers = new MTCustomQueue<AbstractHandler>();
122 //readonly MTQueue<AbstractHandler> m_handlers = new MTQueue<AbstractHandler>();
107
123
108 public Promise() {
124 public Promise() {
109 }
125 }
110
126
111 public Promise(IPromise parent) {
127 public Promise(IPromise parent) {
112 if (parent != null)
128 if (parent != null)
113 AddHandler(
129 AddHandler<T>(
114 null,
130 null,
115 null,
131 null,
116 () => {
132 () => {
@@ -215,49 +231,6 namespace Implab {
215 }
231 }
216 }
232 }
217
233
218 public IPromise<T> Then(Action<T> success, Func<Exception,T> error, Action cancel) {
219 if (success == null && error == null && cancel == null)
220 return this;
221
222 var medium = new Promise<T>(this);
223
224 AddHandler(success, error, cancel, medium, true);
225
226 return medium;
227 }
228
229 /// <summary>
230 /// Adds new handlers to this promise.
231 /// </summary>
232 /// <param name="success">The handler of the successfully completed operation.
233 /// This handler will recieve an operation result as a parameter.</param>
234 /// <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>
235 /// <returns>The new promise chained to this one.</returns>
236 public IPromise<T> Then(Action<T> success, Func<Exception,T> error) {
237 if (success == null && error == null)
238 return this;
239
240 var medium = new Promise<T>(this);
241
242 AddHandler(success, error, null, medium, true);
243
244 return medium;
245 }
246
247
248
249
250 public IPromise<T> Then(Action<T> success) {
251 if (success == null)
252 return this;
253
254 var medium = new Promise<T>(this);
255
256 AddHandler(success, null, null, medium, true);
257
258 return medium;
259 }
260
261 /// <summary>
234 /// <summary>
262 /// Последний обработчик в цепочки обещаний.
235 /// Последний обработчик в цепочки обещаний.
263 /// </summary>
236 /// </summary>
@@ -279,13 +252,19 namespace Implab {
279 if (success == null && error == null && cancel == null)
252 if (success == null && error == null && cancel == null)
280 return;
253 return;
281
254
282 Func<Exception,T> errorHandler = null;
255 AddHandler(
283 if (error != null)
256 success != null ? new Func<T,T>(x => {
284 errorHandler = err => {
257 success(x);
285 error(err);
258 return x;
259 }) : null,
260 error != null ? new Func<Exception,T>(e => {
261 error(e);
286 return default(T);
262 return default(T);
287 };
263 }) : null,
288 AddHandler(success, errorHandler, cancel, null, false);
264 cancel,
265 null,
266 false
267 );
289 }
268 }
290
269
291 public void On(Action<T> success, Action<Exception> error) {
270 public void On(Action<T> success, Action<Exception> error) {
@@ -299,7 +278,10 namespace Implab {
299 public void On(Action handler, PromiseEventType events) {
278 public void On(Action handler, PromiseEventType events) {
300 Safe.ArgumentNotNull(handler, "handler");
279 Safe.ArgumentNotNull(handler, "handler");
301
280
302 Action<T> success = events.HasFlag(PromiseEventType.Success) ? new Action<T>(x => handler()) : null;
281 Func<T,T> success = events.HasFlag(PromiseEventType.Success) ? new Func<T,T>(x => {
282 handler();
283 return x;
284 }) : null;
303 Func<Exception,T> error = events.HasFlag(PromiseEventType.Error) ? new Func<Exception,T>(e => {
285 Func<Exception,T> error = events.HasFlag(PromiseEventType.Error) ? new Func<Exception,T>(e => {
304 handler();
286 handler();
305 return default(T);
287 return default(T);
@@ -363,39 +345,11 namespace Implab {
363 // создаем прицепленное обещание
345 // создаем прицепленное обещание
364 var medium = new Promise<TNew>(this);
346 var medium = new Promise<TNew>(this);
365
347
366 Action<T> resultHandler = result => medium.Resolve(mapper(result));
367 Func<Exception,T> errorHandler;
368 if (error != null)
369 errorHandler = e => {
370 try {
371 medium.Resolve(error(e));
372 } catch (Exception e2) {
373 // в случае ошибки нужно передать исключение дальше по цепочке
374 medium.Reject(e2);
375 }
376 return default(T);
377 };
378 else
379 errorHandler = e => {
380 medium.Reject(e);
381 return default(T);
382 };
383
384 Action cancelHandler;
385 if (cancel != null)
386 cancelHandler = () => {
387 cancel();
388 medium.Cancel();
389 };
390 else
391 cancelHandler = medium.Cancel;
392
393
394 AddHandler(
348 AddHandler(
395 resultHandler,
349 mapper,
396 errorHandler,
350 error,
397 cancelHandler,
351 cancel,
398 null,
352 medium,
399 true
353 true
400 );
354 );
401
355
@@ -431,9 +385,9 namespace Implab {
431 // передать через него результаты работы.
385 // передать через него результаты работы.
432 var medium = new Promise<TNew>(this);
386 var medium = new Promise<TNew>(this);
433
387
434 Action<T> resultHandler = delegate(T result) {
388 Func<T,T> resultHandler = delegate(T result) {
435 if (medium.IsCancelled)
389 if (medium.IsCancelled)
436 return;
390 return default(T);
437
391
438 var promise = chained(result);
392 var promise = chained(result);
439
393
@@ -454,6 +408,8 namespace Implab {
454 promise.Cancel();
408 promise.Cancel();
455 }
409 }
456 );
410 );
411
412 return default(T);
457 };
413 };
458
414
459 Func<Exception,T> errorHandler;
415 Func<Exception,T> errorHandler;
@@ -534,7 +490,10 namespace Implab {
534 var medium = new Promise<T>(this);
490 var medium = new Promise<T>(this);
535
491
536 AddHandler(
492 AddHandler(
537 x => handler(),
493 x => {
494 handler();
495 return x;
496 },
538 e => {
497 e => {
539 handler();
498 handler();
540 throw new TransientPromiseException(e);
499 throw new TransientPromiseException(e);
@@ -600,16 +559,11 namespace Implab {
600 return Join(Timeout.Infinite);
559 return Join(Timeout.Infinite);
601 }
560 }
602
561
603 void AddHandler(Action<T> success, Func<Exception,T> error, Action cancel, Promise<T> medium, bool inc) {
562 void AddHandler<T2>(Func<T,T2> success, Func<Exception,T2> error, Action cancel, Promise<T2> medium, bool inc) {
604 if (inc)
563 if (inc)
605 Interlocked.Increment(ref m_childrenCount);
564 Interlocked.Increment(ref m_childrenCount);
606
565
607 var handler = new HandlerDescriptor {
566 AbstractHandler handler = new HandlerDescriptor<T2>(success, error, cancel, medium);
608 resultHandler = success,
609 errorHandler = error,
610 cancellHandler = cancel,
611 medium = medium
612 };
613
567
614 bool queued;
568 bool queued;
615
569
@@ -631,7 +585,7 namespace Implab {
631 InvokeHandler(handler);
585 InvokeHandler(handler);
632 }
586 }
633
587
634 protected virtual void InvokeHandler(HandlerDescriptor handler) {
588 protected virtual void InvokeHandler(AbstractHandler handler) {
635 switch (m_state) {
589 switch (m_state) {
636 case SUCCEEDED_STATE:
590 case SUCCEEDED_STATE:
637 handler.Resolve(m_result);
591 handler.Resolve(m_result);
@@ -649,7 +603,7 namespace Implab {
649 }
603 }
650
604
651 void OnStateChanged() {
605 void OnStateChanged() {
652 HandlerDescriptor handler;
606 AbstractHandler handler;
653 while (m_handlers.TryDequeue(out handler))
607 while (m_handlers.TryDequeue(out handler))
654 InvokeHandler(handler);
608 InvokeHandler(handler);
655 }
609 }
@@ -688,16 +642,13 namespace Implab {
688 var dest = i;
642 var dest = i;
689
643
690 if (promises[i] != null) {
644 if (promises[i] != null) {
691 promises[i].Then(
645 promises[i].On(
692 x => {
646 x => {
693 result[dest] = x;
647 result[dest] = x;
694 if (Interlocked.Decrement(ref pending) == 0)
648 if (Interlocked.Decrement(ref pending) == 0)
695 promise.Resolve(result);
649 promise.Resolve(result);
696 },
650 },
697 e => {
651 promise.Reject
698 promise.Reject(e);
699 return default(T);
700 }
701 );
652 );
702 } else {
653 } else {
703 if (Interlocked.Decrement(ref pending) == 0)
654 if (Interlocked.Decrement(ref pending) == 0)
@@ -776,7 +727,10 namespace Implab {
776
727
777 IPromise IPromise.Then(Action success, Action<Exception> error, Action cancel) {
728 IPromise IPromise.Then(Action success, Action<Exception> error, Action cancel) {
778 return Then(
729 return Then(
779 success != null ? new Action<T>(x => success()) : null,
730 success != null ? new Func<T,T>(x => {
731 success();
732 return x;
733 }) : null,
780 error != null ? new Func<Exception,T>(e => {
734 error != null ? new Func<Exception,T>(e => {
781 error(e);
735 error(e);
782 return default(T);
736 return default(T);
@@ -787,7 +741,10 namespace Implab {
787
741
788 IPromise IPromise.Then(Action success, Action<Exception> error) {
742 IPromise IPromise.Then(Action success, Action<Exception> error) {
789 return Then(
743 return Then(
790 success != null ? new Action<T>(x => success()) : null,
744 success != null ? new Func<T,T>(x => {
745 success();
746 return x;
747 }) : null,
791 error != null ? new Func<Exception,T>(e => {
748 error != null ? new Func<Exception,T>(e => {
792 error(e);
749 error(e);
793 return default(T);
750 return default(T);
@@ -797,7 +754,10 namespace Implab {
797
754
798 IPromise IPromise.Then(Action success) {
755 IPromise IPromise.Then(Action success) {
799 Safe.ArgumentNotNull(success, "success");
756 Safe.ArgumentNotNull(success, "success");
800 return Then(x => success());
757 return Then(x => {
758 success();
759 return x;
760 });
801 }
761 }
802
762
803 IPromise IPromise.Chain(Func<IPromise> chained, Func<Exception,IPromise> error, Action cancel) {
763 IPromise IPromise.Chain(Func<IPromise> chained, Func<Exception,IPromise> error, Action cancel) {
@@ -809,9 +769,9 namespace Implab {
809
769
810 var medium = new Promise<object>(this);
770 var medium = new Promise<object>(this);
811
771
812 Action<T> resultHandler = delegate {
772 Func<T,T> resultHandler = delegate {
813 if (medium.IsCancelled)
773 if (medium.IsCancelled)
814 return;
774 return default(T);
815
775
816 var promise = chained();
776 var promise = chained();
817
777
@@ -828,6 +788,8 namespace Implab {
828 if (promise.IsExclusive)
788 if (promise.IsExclusive)
829 promise.Cancel();
789 promise.Cancel();
830 });
790 });
791
792 return default(T);
831 };
793 };
832
794
833 Func<Exception,T> errorHandler;
795 Func<Exception,T> errorHandler;
@@ -14,7 +14,7 namespace Implab {
14 Safe.ArgumentNotNull(context, "context");
14 Safe.ArgumentNotNull(context, "context");
15 m_context = context;
15 m_context = context;
16 }
16 }
17 protected override void InvokeHandler(HandlerDescriptor handler) {
17 protected override void InvokeHandler(AbstractHandler handler) {
18 m_context.Post(x => base.InvokeHandler(handler),null);
18 m_context.Post(x => base.InvokeHandler(handler),null);
19 }
19 }
20 }
20 }
General Comments 0
You need to be logged in to leave comments. Login now