Mercurial > pub > ImplabNet
comparison Implab/CancellationToken.cs @ 240:fa6cbf4d8841 v3
refactoring, moving to dotnercore, simplifying promises
author | cin |
---|---|
date | Tue, 23 Jan 2018 19:39:21 +0300 |
parents | |
children | 5cb4826c2c2a |
comparison
equal
deleted
inserted
replaced
239:eedf4d834e67 | 240:fa6cbf4d8841 |
---|---|
1 using System; | |
2 using System.Threading; | |
3 using Implab.Parallels; | |
4 | |
5 namespace Implab { | |
6 public class CancellationToken : ICancellationToken { | |
7 const int CANCEL_NOT_REQUESTED = 0; | |
8 const int CANCEL_REQUESTING = 1; | |
9 const int CANCEL_REQUESTED = 2; | |
10 | |
11 volatile int m_state = CANCEL_NOT_REQUESTED; | |
12 | |
13 Action<Exception> m_handler; | |
14 | |
15 Parallels.SimpleAsyncQueue<Action<Exception>> m_handlers; | |
16 | |
17 public bool IsCancellationRequested { | |
18 get { return m_state == CANCEL_REQUESTED; } | |
19 } | |
20 | |
21 public Exception CancellationReason { | |
22 get; set; | |
23 } | |
24 | |
25 public void CancellationRequested(Action<Exception> handler) { | |
26 Safe.ArgumentNotNull(handler, nameof(handler)); | |
27 if (IsCancellationRequested) { | |
28 handler(CancellationReason); | |
29 } else { | |
30 EnqueueHandler(handler); | |
31 if (IsCancellationRequested && TryDequeueHandler(out handler)) | |
32 handler(CancellationReason); | |
33 } | |
34 } | |
35 | |
36 bool TryDequeueHandler(out Action<Exception> handler) { | |
37 handler = Interlocked.Exchange(ref m_handler, null); | |
38 if (handler != null) | |
39 return true; | |
40 else if (m_handlers != null) | |
41 return m_handlers.TryDequeue(out handler); | |
42 else | |
43 return false; | |
44 } | |
45 | |
46 void EnqueueHandler(Action<Exception> handler) { | |
47 if (Interlocked.CompareExchange(ref m_handler, handler, null) != null) { | |
48 if (m_handlers == null) | |
49 // compare-exchange will fprotect from loosing already created queue | |
50 Interlocked.CompareExchange(ref m_handlers, new SimpleAsyncQueue<Action<Exception>>(), null); | |
51 m_handlers.Enqueue(handler); | |
52 } | |
53 } | |
54 | |
55 void RequestCancellation(Exception reason) { | |
56 if (Interlocked.CompareExchange(ref m_state, CANCEL_REQUESTING, CANCEL_NOT_REQUESTED) == CANCEL_NOT_REQUESTED) { | |
57 if (reason == null) | |
58 reason = new OperationCanceledException(); | |
59 CancellationReason = reason; | |
60 m_state = CANCEL_REQUESTED; | |
61 } | |
62 } | |
63 | |
64 } | |
65 } |