##// END OF EJS Templates
Reworked cancelation handling, if the cancel handler isn't specified the OperationCanceledException will be handled by the error handler...
cin -
r187:dd4a3590f9c6 ref20160224
parent child
Show More
@@ -0,0 +1,45
1 using System;
2 using System.Threading;
3
4 namespace Implab {
5 /// <summary>
6 /// Базовый класс для реализации задачь. Задача представляет собой некторое
7 /// действие, которое можно иницировать и обработать результат его выполнения
8 /// в виде обещания, для этого оно реализует интерфейс <see cref="IPromise"/>.
9 /// </summary>
10 /// <remarks>
11 /// Данный класс определяет стандартное поведение при обработки результатов, в частности
12 /// обработку <see cref="System.OperationCanceledException"/> и <see cref="PromiseTransientException"/>
13 /// </remarks>
14 public abstract class AbstractTask : AbstractPromise {
15 int m_cancelationLock;
16
17 /// <summary>
18 /// Получает эксклюзивное право отмены задания, используется для отмены задания до начала его выполнения.
19 /// </summary>
20 /// <returns><c>true</c>, if cancelation was locked, <c>false</c> otherwise.</returns>
21 protected bool LockCancelation() {
22 return 0 == Interlocked.CompareExchange(ref m_cancelationLock, 1, 0);
23 }
24
25
26
27 protected void SetErrorInternal(Exception error) {
28 // unwrap
29 while (error is PromiseTransientException && error.InnerException != null)
30 error = error.InnerException;
31
32 if (error is OperationCanceledException)
33 SetCancelled(error);
34 else
35 SetError(error);
36 }
37
38 protected void SetCancelledInternal(Exception reason) {
39 SetCancelled(
40 reason == null ? new OperationCanceledException() : reason is OperationCanceledException ? reason : new OperationCanceledException(null, reason)
41 );
42 }
43 }
44 }
45
@@ -0,0 +1,36
1 using System;
2 using System.Threading;
3
4 namespace Implab {
5 public abstract class AbstractTask<T> : AbstractPromise<T> {
6 int m_cancelationLock;
7
8 /// <summary>
9 /// Получает эксклюзивное право отмены задания, используется для отмены задания до начала его выполнения.
10 /// </summary>
11 /// <returns><c>true</c>, if cancelation was locked, <c>false</c> otherwise.</returns>
12 protected bool LockCancelation() {
13 return 0 == Interlocked.CompareExchange(ref m_cancelationLock, 1, 0);
14 }
15
16
17
18 protected void SetErrorInternal(Exception error) {
19 // unwrap
20 while (error is PromiseTransientException && error.InnerException != null)
21 error = error.InnerException;
22
23 if (error is OperationCanceledException)
24 SetCancelled(error);
25 else
26 SetError(error);
27 }
28
29 protected void SetCancelledInternal(Exception reason) {
30 SetCancelled(
31 reason == null ? new OperationCanceledException() : reason is OperationCanceledException ? reason : new OperationCanceledException(null, reason)
32 );
33 }
34 }
35 }
36
@@ -21,8 +21,10 namespace Implab {
21 21 if (m_task != null && LockCancelation()) {
22 22 try {
23 23 var p = m_task();
24 p.On(SetResult, HandleErrorInternal, SetCancelled);
24 p.On(SetResult, HandleErrorInternal, HandleCancelInternal);
25 25 CancellationRequested(p.Cancel);
26 } catch (OperationCanceledException reason){
27 HandleCancelInternal(reason);
26 28 } catch(Exception err) {
27 29 HandleErrorInternal(err);
28 30 }
@@ -2,12 +2,10
2 2 using System.Threading;
3 3
4 4 namespace Implab {
5 public class ActionChainTaskBase : AbstractPromise {
5 public class ActionChainTaskBase : AbstractTask {
6 6 readonly Func<Exception, IPromise> m_error;
7 7 readonly Func<Exception, IPromise> m_cancel;
8 8
9 int m_cancelationLock;
10
11 9 protected ActionChainTaskBase(Func<Exception, IPromise> error, Func<Exception, IPromise> cancel, bool autoCancellable) {
12 10 m_error = error;
13 11 m_cancel = cancel;
@@ -21,55 +19,44 namespace Implab {
21 19 }
22 20
23 21 public override void CancelOperation(Exception reason) {
24 if (LockCancelation()) {
25 if (!(reason is OperationCanceledException))
26 reason = reason != null ? new OperationCanceledException(null, reason) : new OperationCanceledException();
27
28 if (m_cancel != null) {
29 try {
30 m_cancel(reason).On(SetResult, HandleErrorInternal, HandleCancelInternal);
31 } catch (Exception err) {
32 HandleErrorInternal(err);
33 }
34 } else {
35 HandleErrorInternal(reason);
22 if (LockCancelation())
23 // отмена вызвана до начала выполнения задачи
24 HandleCancelInternal(reason);
25 }
26
27 protected void HandleCancelInternal(Exception reason) {
28 if (m_cancel != null) {
29 try {
30 // вызываем обработчик отмены
31 var p = m_cancel(reason);
32 p.On(SetResult, HandleErrorInternal, SetCancelledInternal);
33 // сообщаем асинхронной операции, что клиент уже не хочет получать результат
34 // т.е. если он инициировал отмену, задача отменилась, вызвался обрабочик отмены
35 // отбработчику сообщили, что результат уже не нужен и уже сам обработчик решает
36 // отдавать ли результат или подтвердить отмену (или вернуть ошибку).
37 CancellationRequested(p.Cancel);
38 } catch (Exception err) {
39 HandleErrorInternal(err);
36 40 }
41 } else {
42 HandleErrorInternal(reason ?? new OperationCanceledException());
37 43 }
38 44 }
39 45
40 void HandleCancelInternal(Exception reason) {
41 if (!(reason is OperationCanceledException))
42 reason = reason != null ? new OperationCanceledException(null, reason) : new OperationCanceledException();
43 HandleErrorInternal(reason);
44 }
45
46 void HandleErrorInternal(Exception error) {
46 protected void HandleErrorInternal(Exception error) {
47 47 if (m_error != null) {
48 48 try {
49 49 var p = m_error(error);
50 p.On(SetResult, SetError, SetCancelled);
50 p.On(SetResult, SetErrorInternal, SetCancelledInternal);
51 51 CancellationRequested(p.Cancel);
52 52 } catch (Exception err) {
53 error = err;
53 SetErrorInternal(error);
54 54 }
55 55 } else {
56 56 SetErrorInternal(error);
57 57 }
58 58 }
59 59
60 void SetErrorInternal(Exception error) {
61 while (error is PromiseTransientException)
62 error = error.InnerException;
63
64 if (error is OperationCanceledException)
65 SetCancelled(error);
66 else
67 SetError(error);
68 }
69
70 protected bool LockCancelation() {
71 return 0 == Interlocked.CompareExchange(ref m_cancelationLock, 1, 0);
72 }
73 60 }
74 61 }
75 62
@@ -12,8 +12,10 namespace Implab {
12 12 if (m_task != null && LockCancelation()) {
13 13 try {
14 14 var p = m_task(value);
15 p.On(SetResult, HandleErrorInternal, SetCancelled);
15 p.On(SetResult, HandleErrorInternal, HandleCancelInternal);
16 16 CancellationRequested(p.Cancel);
17 } catch (OperationCanceledException reason) {
18 HandleCancelInternal(reason);
17 19 } catch(Exception err) {
18 20 HandleErrorInternal(err);
19 21 }
@@ -12,6 +12,8 namespace Implab {
12 12 try {
13 13 m_task();
14 14 SetResult();
15 } catch(OperationCanceledException reason) {
16 HandleCancelInternal(reason);
15 17 } catch(Exception err) {
16 18 HandleErrorInternal(err);
17 19 }
@@ -1,13 +1,10
1 1 using System;
2 using System.Threading;
3 2
4 3 namespace Implab {
5 public class ActionTaskBase : AbstractPromise {
4 public class ActionTaskBase : AbstractTask {
6 5 readonly Action<Exception> m_cancel;
7 6 readonly Action<Exception> m_error;
8 7
9 int m_cancelationLock;
10
11 8 protected ActionTaskBase( Action<Exception> error, Action<Exception> cancel, bool autoCancellable) {
12 9 m_error = error;
13 10 m_cancel = cancel;
@@ -21,37 +18,36 namespace Implab {
21 18 HandleErrorInternal(error);
22 19 }
23 20
21 public override void CancelOperation(Exception reason) {
22 if (LockCancelation())
23 HandleCancelInternal(reason);
24 }
25
24 26 protected void HandleErrorInternal(Exception error) {
25 27 if (m_error != null) {
26 28 try {
27 29 m_error(error);
28 30 SetResult();
29 31 } catch(Exception err) {
30 SetError(err);
32 SetErrorInternal(err);
31 33 }
32 34 } else {
33 SetError(error);
35 SetErrorInternal(error);
34 36 }
35 37 }
36 38
37 public override void CancelOperation(Exception reason) {
38 if (LockCancelation()) {
39 if (m_cancel != null) {
40 try {
41 m_cancel(reason);
42 SetResult();
43 } catch (Exception err) {
44 HandleErrorInternal(err);
45 }
46 } else {
47 SetCancelled(reason);
39 protected void HandleCancelInternal(Exception error) {
40 if (m_cancel != null) {
41 try {
42 m_cancel(error);
43 SetResult();
44 } catch(Exception err) {
45 HandleErrorInternal(err);
48 46 }
47 } else {
48 HandleErrorInternal(error ?? new OperationCanceledException());
49 49 }
50 50 }
51
52 protected bool LockCancelation() {
53 return 0 == Interlocked.CompareExchange(ref m_cancelationLock, 1, 0);
54 }
55 51 }
56 52 }
57 53
@@ -12,6 +12,8 namespace Implab {
12 12 try {
13 13 m_task(value);
14 14 SetResult();
15 } catch(OperationCanceledException reason) {
16 HandleCancelInternal(reason);
15 17 } catch(Exception err) {
16 18 HandleErrorInternal(err);
17 19 }
@@ -137,10 +137,6 namespace Implab.Components {
137 137 }
138 138 }
139 139 throw new PromiseTransientException(e);
140 },
141 r => {
142 // handle cancellation as exception
143 throw new OperationCanceledException("The operation has been cancelled", r);
144 140 }
145 141 );
146 142
@@ -194,7 +190,13 namespace Implab.Components {
194 190 if (current == null) {
195 191 stop.Resolve();
196 192 } else {
197 current.On(stop.Resolve, stop.Reject, e => stop.Resolve());
193 // связваем текущую операцию с операцией остановки
194 current.On(
195 stop.Resolve, // если текущая операция заверщилась, то можно начинать остановку
196 stop.Reject, // если текущая операция дала ошибку - то все плохо, нельзя продолжать
197 e => stop.Resolve() // если текущая отменилась, то можно начинать остановку
198 );
199 // посылаем текущей операции сигнал остановки
198 200 current.Cancel();
199 201 }
200 202 }
@@ -13,8 +13,10 namespace Implab {
13 13 if (m_task != null && LockCancelation()) {
14 14 try {
15 15 var operation = m_task();
16 operation.On(SetResult, HandleErrorInternal, SetCancelled);
16 operation.On(SetResult, HandleErrorInternal, HandleCancelInternal);
17 17 CancellationRequested(operation.Cancel);
18 } catch (OperationCanceledException reason) {
19 HandleCancelInternal(reason);
18 20 } catch (Exception err) {
19 21 HandleErrorInternal(err);
20 22 }
@@ -1,13 +1,10
1 1 using System;
2 using System.Threading;
3 2
4 3 namespace Implab {
5 public class FuncChainTaskBase<TResult> : AbstractPromise<TResult> {
4 public class FuncChainTaskBase<TResult> : AbstractTask<TResult> {
6 5 readonly Func<Exception, IPromise<TResult>> m_error;
7 6 readonly Func<Exception, IPromise<TResult>> m_cancel;
8 7
9 int m_cancelationLock;
10
11 8 protected FuncChainTaskBase( Func<Exception, IPromise<TResult>> error, Func<Exception, IPromise<TResult>> cancel, bool autoCancellable) {
12 9 m_error = error;
13 10 m_cancel = cancel;
@@ -21,37 +18,36 namespace Implab {
21 18 }
22 19
23 20 public override void CancelOperation(Exception reason) {
24 if (LockCancelation()) {
25 if (m_cancel != null) {
26 try {
27 m_cancel(reason).On(SetResult, HandleErrorInternal, SetCancelled);
28 } catch (Exception err) {
29 HandleErrorInternal(err);
30 }
31 } else {
32 SetCancelled(reason);
33 }
34 }
35
21 if (LockCancelation())
22 HandleCancelInternal(reason);
36 23 }
37 24
38 25 protected void HandleErrorInternal(Exception error) {
39 26 if (m_error != null) {
40 27 try {
41 var operation = m_error(error);
42
43 operation.On(SetResult, SetError, SetCancelled);
44 CancellationRequested(operation.Cancel);
28 var p = m_error(error);
29 p.On(SetResult, SetErrorInternal, SetCancelledInternal);
30 CancellationRequested(p.Cancel);
45 31 } catch(Exception err) {
46 SetError(err);
32 SetErrorInternal(err);
47 33 }
48 34 } else {
49 SetError(error);
35 SetErrorInternal(error);
50 36 }
51 37 }
52 38
53 protected bool LockCancelation() {
54 return 0 == Interlocked.CompareExchange(ref m_cancelationLock, 1, 0);
39 protected void HandleCancelInternal(Exception reason) {
40 if (m_cancel != null) {
41 try {
42 var p = m_cancel(reason);
43 p.On(SetResult, HandleErrorInternal, SetCancelledInternal);
44 CancellationRequested(p.Cancel);
45 } catch (Exception err) {
46 HandleErrorInternal(err);
47 }
48 } else {
49 HandleErrorInternal(reason ?? new OperationCanceledException());
50 }
55 51 }
56 52 }
57 53 }
@@ -14,6 +14,8 namespace Implab {
14 14 var operation = m_task(value);
15 15 operation.On(SetResult, HandleErrorInternal, SetCancelled);
16 16 CancellationRequested(operation.Cancel);
17 } catch (OperationCanceledException reason) {
18 HandleCancelInternal(reason);
17 19 } catch (Exception err) {
18 20 HandleErrorInternal(err);
19 21 }
@@ -13,6 +13,8 namespace Implab {
13 13 if (m_task != null && LockCancelation()) {
14 14 try {
15 15 SetResult(m_task());
16 } catch(OperationCanceledException reason) {
17 HandleCancelInternal(reason);
16 18 } catch(Exception err) {
17 19 HandleErrorInternal(err);
18 20 }
@@ -1,13 +1,10
1 1 using System;
2 using System.Threading;
3 2
4 3 namespace Implab {
5 public class FuncTaskBase<TResult> : AbstractPromise<TResult> {
4 public class FuncTaskBase<TResult> : AbstractTask<TResult> {
6 5 readonly Func<Exception, TResult> m_cancel;
7 6 readonly Func<Exception, TResult> m_error;
8 7
9 int m_cancelationLock;
10
11 8 protected FuncTaskBase( Func<Exception, TResult> error, Func<Exception, TResult> cancel, bool autoCancellable) {
12 9 m_error = error;
13 10 m_cancel = cancel;
@@ -26,30 +23,30 namespace Implab {
26 23 try {
27 24 SetResult(m_error(error));
28 25 } catch(Exception err) {
29 SetError(err);
26 SetErrorInternal(err);
30 27 }
31 28 } else {
32 SetError(error);
29 SetErrorInternal(error);
33 30 }
34 31 }
35 32
36 33 public override void CancelOperation(Exception reason) {
37 if (LockCancelation()) {
38 if (m_cancel != null) {
39 try {
40 SetResult(m_cancel(reason));
41 } catch (Exception err) {
42 HandleErrorInternal(err);
43 }
44 } else {
45 SetCancelled(reason);
34 if (LockCancelation())
35 HandleCancelInternal(reason);
36 }
37
38 protected void HandleCancelInternal(Exception reason) {
39 if (m_cancel != null) {
40 try {
41 SetResult(m_cancel(reason));
42 } catch (Exception err) {
43 HandleErrorInternal(err);
46 44 }
45 } else {
46 HandleErrorInternal(reason ?? new OperationCanceledException());
47 47 }
48 48 }
49 49
50 protected bool LockCancelation() {
51 return 0 == Interlocked.CompareExchange(ref m_cancelationLock, 1, 0);
52 }
53 50 }
54 51 }
55 52
@@ -12,7 +12,9 namespace Implab {
12 12 if (m_task != null && LockCancelation()) {
13 13 try {
14 14 SetResult(m_task(value));
15 } catch (Exception err) {
15 } catch(OperationCanceledException reason) {
16 HandleCancelInternal(reason);
17 } catch(Exception err) {
16 18 HandleErrorInternal(err);
17 19 }
18 20 }
@@ -193,6 +193,8
193 193 <Compile Include="Automaton\AutomatonConst.cs" />
194 194 <Compile Include="Automaton\RegularExpressions\RegularDFA.cs" />
195 195 <Compile Include="Components\LazyAndWeak.cs" />
196 <Compile Include="AbstractTask.cs" />
197 <Compile Include="AbstractTaskT.cs" />
196 198 </ItemGroup>
197 199 <Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
198 200 <ItemGroup />
General Comments 0
You need to be logged in to leave comments. Login now