CancellationToken.cs
64 lines
| 2.2 KiB
| text/x-csharp
|
CSharpLexer
/ Implab / CancellationToken.cs
cin
|
r240 | using System; | |
using System.Threading; | |||
using Implab.Parallels; | |||
namespace Implab { | |||
public class CancellationToken : ICancellationToken { | |||
const int CANCEL_NOT_REQUESTED = 0; | |||
const int CANCEL_REQUESTING = 1; | |||
const int CANCEL_REQUESTED = 2; | |||
volatile int m_state = CANCEL_NOT_REQUESTED; | |||
Action<Exception> m_handler; | |||
Parallels.SimpleAsyncQueue<Action<Exception>> m_handlers; | |||
public bool IsCancellationRequested { | |||
get { return m_state == CANCEL_REQUESTED; } | |||
} | |||
public Exception CancellationReason { | |||
get; set; | |||
} | |||
public void CancellationRequested(Action<Exception> handler) { | |||
Safe.ArgumentNotNull(handler, nameof(handler)); | |||
if (IsCancellationRequested) { | |||
handler(CancellationReason); | |||
} else { | |||
EnqueueHandler(handler); | |||
if (IsCancellationRequested && TryDequeueHandler(out handler)) | |||
handler(CancellationReason); | |||
} | |||
} | |||
bool TryDequeueHandler(out Action<Exception> handler) { | |||
handler = Interlocked.Exchange(ref m_handler, null); | |||
if (handler != null) | |||
return true; | |||
else if (m_handlers != null) | |||
return m_handlers.TryDequeue(out handler); | |||
else | |||
return false; | |||
} | |||
void EnqueueHandler(Action<Exception> handler) { | |||
if (Interlocked.CompareExchange(ref m_handler, handler, null) != null) { | |||
if (m_handlers == null) | |||
// compare-exchange will fprotect from loosing already created queue | |||
Interlocked.CompareExchange(ref m_handlers, new SimpleAsyncQueue<Action<Exception>>(), null); | |||
m_handlers.Enqueue(handler); | |||
} | |||
} | |||
void RequestCancellation(Exception reason) { | |||
if (Interlocked.CompareExchange(ref m_state, CANCEL_REQUESTING, CANCEL_NOT_REQUESTED) == CANCEL_NOT_REQUESTED) { | |||
if (reason == null) | |||
reason = new OperationCanceledException(); | |||
CancellationReason = reason; | |||
m_state = CANCEL_REQUESTED; | |||
} | |||
} | |||
} | |||
} |