##// 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 if (m_task != null && LockCancelation()) {
21 if (m_task != null && LockCancelation()) {
22 try {
22 try {
23 var p = m_task();
23 var p = m_task();
24 p.On(SetResult, HandleErrorInternal, SetCancelled);
24 p.On(SetResult, HandleErrorInternal, HandleCancelInternal);
25 CancellationRequested(p.Cancel);
25 CancellationRequested(p.Cancel);
26 } catch (OperationCanceledException reason){
27 HandleCancelInternal(reason);
26 } catch(Exception err) {
28 } catch(Exception err) {
27 HandleErrorInternal(err);
29 HandleErrorInternal(err);
28 }
30 }
@@ -2,12 +2,10
2 using System.Threading;
2 using System.Threading;
3
3
4 namespace Implab {
4 namespace Implab {
5 public class ActionChainTaskBase : AbstractPromise {
5 public class ActionChainTaskBase : AbstractTask {
6 readonly Func<Exception, IPromise> m_error;
6 readonly Func<Exception, IPromise> m_error;
7 readonly Func<Exception, IPromise> m_cancel;
7 readonly Func<Exception, IPromise> m_cancel;
8
8
9 int m_cancelationLock;
10
11 protected ActionChainTaskBase(Func<Exception, IPromise> error, Func<Exception, IPromise> cancel, bool autoCancellable) {
9 protected ActionChainTaskBase(Func<Exception, IPromise> error, Func<Exception, IPromise> cancel, bool autoCancellable) {
12 m_error = error;
10 m_error = error;
13 m_cancel = cancel;
11 m_cancel = cancel;
@@ -21,55 +19,44 namespace Implab {
21 }
19 }
22
20
23 public override void CancelOperation(Exception reason) {
21 public override void CancelOperation(Exception reason) {
24 if (LockCancelation()) {
22 if (LockCancelation())
25 if (!(reason is OperationCanceledException))
23 // отмена вызвана до начала выполнения задачи
26 reason = reason != null ? new OperationCanceledException(null, reason) : new OperationCanceledException();
24 HandleCancelInternal(reason);
27
25 }
28 if (m_cancel != null) {
26
29 try {
27 protected void HandleCancelInternal(Exception reason) {
30 m_cancel(reason).On(SetResult, HandleErrorInternal, HandleCancelInternal);
28 if (m_cancel != null) {
31 } catch (Exception err) {
29 try {
32 HandleErrorInternal(err);
30 // вызываем обработчик отмены
33 }
31 var p = m_cancel(reason);
34 } else {
32 p.On(SetResult, HandleErrorInternal, SetCancelledInternal);
35 HandleErrorInternal(reason);
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) {
46 protected void HandleErrorInternal(Exception error) {
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) {
47 if (m_error != null) {
47 if (m_error != null) {
48 try {
48 try {
49 var p = m_error(error);
49 var p = m_error(error);
50 p.On(SetResult, SetError, SetCancelled);
50 p.On(SetResult, SetErrorInternal, SetCancelledInternal);
51 CancellationRequested(p.Cancel);
51 CancellationRequested(p.Cancel);
52 } catch (Exception err) {
52 } catch (Exception err) {
53 error = err;
53 SetErrorInternal(error);
54 }
54 }
55 } else {
55 } else {
56 SetErrorInternal(error);
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 if (m_task != null && LockCancelation()) {
12 if (m_task != null && LockCancelation()) {
13 try {
13 try {
14 var p = m_task(value);
14 var p = m_task(value);
15 p.On(SetResult, HandleErrorInternal, SetCancelled);
15 p.On(SetResult, HandleErrorInternal, HandleCancelInternal);
16 CancellationRequested(p.Cancel);
16 CancellationRequested(p.Cancel);
17 } catch (OperationCanceledException reason) {
18 HandleCancelInternal(reason);
17 } catch(Exception err) {
19 } catch(Exception err) {
18 HandleErrorInternal(err);
20 HandleErrorInternal(err);
19 }
21 }
@@ -12,6 +12,8 namespace Implab {
12 try {
12 try {
13 m_task();
13 m_task();
14 SetResult();
14 SetResult();
15 } catch(OperationCanceledException reason) {
16 HandleCancelInternal(reason);
15 } catch(Exception err) {
17 } catch(Exception err) {
16 HandleErrorInternal(err);
18 HandleErrorInternal(err);
17 }
19 }
@@ -1,13 +1,10
1 using System;
1 using System;
2 using System.Threading;
3
2
4 namespace Implab {
3 namespace Implab {
5 public class ActionTaskBase : AbstractPromise {
4 public class ActionTaskBase : AbstractTask {
6 readonly Action<Exception> m_cancel;
5 readonly Action<Exception> m_cancel;
7 readonly Action<Exception> m_error;
6 readonly Action<Exception> m_error;
8
7
9 int m_cancelationLock;
10
11 protected ActionTaskBase( Action<Exception> error, Action<Exception> cancel, bool autoCancellable) {
8 protected ActionTaskBase( Action<Exception> error, Action<Exception> cancel, bool autoCancellable) {
12 m_error = error;
9 m_error = error;
13 m_cancel = cancel;
10 m_cancel = cancel;
@@ -21,37 +18,36 namespace Implab {
21 HandleErrorInternal(error);
18 HandleErrorInternal(error);
22 }
19 }
23
20
21 public override void CancelOperation(Exception reason) {
22 if (LockCancelation())
23 HandleCancelInternal(reason);
24 }
25
24 protected void HandleErrorInternal(Exception error) {
26 protected void HandleErrorInternal(Exception error) {
25 if (m_error != null) {
27 if (m_error != null) {
26 try {
28 try {
27 m_error(error);
29 m_error(error);
28 SetResult();
30 SetResult();
29 } catch(Exception err) {
31 } catch(Exception err) {
30 SetError(err);
32 SetErrorInternal(err);
31 }
33 }
32 } else {
34 } else {
33 SetError(error);
35 SetErrorInternal(error);
34 }
36 }
35 }
37 }
36
38
37 public override void CancelOperation(Exception reason) {
39 protected void HandleCancelInternal(Exception error) {
38 if (LockCancelation()) {
40 if (m_cancel != null) {
39 if (m_cancel != null) {
41 try {
40 try {
42 m_cancel(error);
41 m_cancel(reason);
43 SetResult();
42 SetResult();
44 } catch(Exception err) {
43 } catch (Exception err) {
45 HandleErrorInternal(err);
44 HandleErrorInternal(err);
45 }
46 } else {
47 SetCancelled(reason);
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 try {
12 try {
13 m_task(value);
13 m_task(value);
14 SetResult();
14 SetResult();
15 } catch(OperationCanceledException reason) {
16 HandleCancelInternal(reason);
15 } catch(Exception err) {
17 } catch(Exception err) {
16 HandleErrorInternal(err);
18 HandleErrorInternal(err);
17 }
19 }
@@ -137,10 +137,6 namespace Implab.Components {
137 }
137 }
138 }
138 }
139 throw new PromiseTransientException(e);
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 if (current == null) {
190 if (current == null) {
195 stop.Resolve();
191 stop.Resolve();
196 } else {
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 current.Cancel();
200 current.Cancel();
199 }
201 }
200 }
202 }
@@ -13,8 +13,10 namespace Implab {
13 if (m_task != null && LockCancelation()) {
13 if (m_task != null && LockCancelation()) {
14 try {
14 try {
15 var operation = m_task();
15 var operation = m_task();
16 operation.On(SetResult, HandleErrorInternal, SetCancelled);
16 operation.On(SetResult, HandleErrorInternal, HandleCancelInternal);
17 CancellationRequested(operation.Cancel);
17 CancellationRequested(operation.Cancel);
18 } catch (OperationCanceledException reason) {
19 HandleCancelInternal(reason);
18 } catch (Exception err) {
20 } catch (Exception err) {
19 HandleErrorInternal(err);
21 HandleErrorInternal(err);
20 }
22 }
@@ -1,13 +1,10
1 using System;
1 using System;
2 using System.Threading;
3
2
4 namespace Implab {
3 namespace Implab {
5 public class FuncChainTaskBase<TResult> : AbstractPromise<TResult> {
4 public class FuncChainTaskBase<TResult> : AbstractTask<TResult> {
6 readonly Func<Exception, IPromise<TResult>> m_error;
5 readonly Func<Exception, IPromise<TResult>> m_error;
7 readonly Func<Exception, IPromise<TResult>> m_cancel;
6 readonly Func<Exception, IPromise<TResult>> m_cancel;
8
7
9 int m_cancelationLock;
10
11 protected FuncChainTaskBase( Func<Exception, IPromise<TResult>> error, Func<Exception, IPromise<TResult>> cancel, bool autoCancellable) {
8 protected FuncChainTaskBase( Func<Exception, IPromise<TResult>> error, Func<Exception, IPromise<TResult>> cancel, bool autoCancellable) {
12 m_error = error;
9 m_error = error;
13 m_cancel = cancel;
10 m_cancel = cancel;
@@ -21,37 +18,36 namespace Implab {
21 }
18 }
22
19
23 public override void CancelOperation(Exception reason) {
20 public override void CancelOperation(Exception reason) {
24 if (LockCancelation()) {
21 if (LockCancelation())
25 if (m_cancel != null) {
22 HandleCancelInternal(reason);
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
36 }
23 }
37
24
38 protected void HandleErrorInternal(Exception error) {
25 protected void HandleErrorInternal(Exception error) {
39 if (m_error != null) {
26 if (m_error != null) {
40 try {
27 try {
41 var operation = m_error(error);
28 var p = m_error(error);
42
29 p.On(SetResult, SetErrorInternal, SetCancelledInternal);
43 operation.On(SetResult, SetError, SetCancelled);
30 CancellationRequested(p.Cancel);
44 CancellationRequested(operation.Cancel);
45 } catch(Exception err) {
31 } catch(Exception err) {
46 SetError(err);
32 SetErrorInternal(err);
47 }
33 }
48 } else {
34 } else {
49 SetError(error);
35 SetErrorInternal(error);
50 }
36 }
51 }
37 }
52
38
53 protected bool LockCancelation() {
39 protected void HandleCancelInternal(Exception reason) {
54 return 0 == Interlocked.CompareExchange(ref m_cancelationLock, 1, 0);
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 var operation = m_task(value);
14 var operation = m_task(value);
15 operation.On(SetResult, HandleErrorInternal, SetCancelled);
15 operation.On(SetResult, HandleErrorInternal, SetCancelled);
16 CancellationRequested(operation.Cancel);
16 CancellationRequested(operation.Cancel);
17 } catch (OperationCanceledException reason) {
18 HandleCancelInternal(reason);
17 } catch (Exception err) {
19 } catch (Exception err) {
18 HandleErrorInternal(err);
20 HandleErrorInternal(err);
19 }
21 }
@@ -13,6 +13,8 namespace Implab {
13 if (m_task != null && LockCancelation()) {
13 if (m_task != null && LockCancelation()) {
14 try {
14 try {
15 SetResult(m_task());
15 SetResult(m_task());
16 } catch(OperationCanceledException reason) {
17 HandleCancelInternal(reason);
16 } catch(Exception err) {
18 } catch(Exception err) {
17 HandleErrorInternal(err);
19 HandleErrorInternal(err);
18 }
20 }
@@ -1,13 +1,10
1 using System;
1 using System;
2 using System.Threading;
3
2
4 namespace Implab {
3 namespace Implab {
5 public class FuncTaskBase<TResult> : AbstractPromise<TResult> {
4 public class FuncTaskBase<TResult> : AbstractTask<TResult> {
6 readonly Func<Exception, TResult> m_cancel;
5 readonly Func<Exception, TResult> m_cancel;
7 readonly Func<Exception, TResult> m_error;
6 readonly Func<Exception, TResult> m_error;
8
7
9 int m_cancelationLock;
10
11 protected FuncTaskBase( Func<Exception, TResult> error, Func<Exception, TResult> cancel, bool autoCancellable) {
8 protected FuncTaskBase( Func<Exception, TResult> error, Func<Exception, TResult> cancel, bool autoCancellable) {
12 m_error = error;
9 m_error = error;
13 m_cancel = cancel;
10 m_cancel = cancel;
@@ -26,30 +23,30 namespace Implab {
26 try {
23 try {
27 SetResult(m_error(error));
24 SetResult(m_error(error));
28 } catch(Exception err) {
25 } catch(Exception err) {
29 SetError(err);
26 SetErrorInternal(err);
30 }
27 }
31 } else {
28 } else {
32 SetError(error);
29 SetErrorInternal(error);
33 }
30 }
34 }
31 }
35
32
36 public override void CancelOperation(Exception reason) {
33 public override void CancelOperation(Exception reason) {
37 if (LockCancelation()) {
34 if (LockCancelation())
38 if (m_cancel != null) {
35 HandleCancelInternal(reason);
39 try {
36 }
40 SetResult(m_cancel(reason));
37
41 } catch (Exception err) {
38 protected void HandleCancelInternal(Exception reason) {
42 HandleErrorInternal(err);
39 if (m_cancel != null) {
43 }
40 try {
44 } else {
41 SetResult(m_cancel(reason));
45 SetCancelled(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 if (m_task != null && LockCancelation()) {
12 if (m_task != null && LockCancelation()) {
13 try {
13 try {
14 SetResult(m_task(value));
14 SetResult(m_task(value));
15 } catch (Exception err) {
15 } catch(OperationCanceledException reason) {
16 HandleCancelInternal(reason);
17 } catch(Exception err) {
16 HandleErrorInternal(err);
18 HandleErrorInternal(err);
17 }
19 }
18 }
20 }
@@ -193,6 +193,8
193 <Compile Include="Automaton\AutomatonConst.cs" />
193 <Compile Include="Automaton\AutomatonConst.cs" />
194 <Compile Include="Automaton\RegularExpressions\RegularDFA.cs" />
194 <Compile Include="Automaton\RegularExpressions\RegularDFA.cs" />
195 <Compile Include="Components\LazyAndWeak.cs" />
195 <Compile Include="Components\LazyAndWeak.cs" />
196 <Compile Include="AbstractTask.cs" />
197 <Compile Include="AbstractTaskT.cs" />
196 </ItemGroup>
198 </ItemGroup>
197 <Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
199 <Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
198 <ItemGroup />
200 <ItemGroup />
General Comments 0
You need to be logged in to leave comments. Login now