Permalink
Fetching contributors…
Cannot retrieve contributors at this time
119 lines (103 sloc) 3.45 KB
//<snippet13>
using System;
using System.Threading;
using System.Threading.Tasks;
class LinkedTokenSourceDemo
{
static void Main()
{
WorkerWithTimer worker = new WorkerWithTimer();
CancellationTokenSource cts = new CancellationTokenSource();
// Task for UI thread, so we can call Task.Wait wait on the main thread.
Task.Run(() =>
{
Console.WriteLine("Press 'c' to cancel within 3 seconds after work begins.");
Console.WriteLine("Or let the task time out by doing nothing.");
if (Console.ReadKey(true).KeyChar == 'c')
cts.Cancel();
});
// Let the user read the UI message.
Thread.Sleep(1000);
// Start the worker task.
Task task = Task.Run(() => worker.DoWork(cts.Token), cts.Token);
try {
task.Wait(cts.Token);
}
catch (OperationCanceledException e) {
if (e.CancellationToken == cts.Token)
Console.WriteLine("Canceled from UI thread throwing OCE.");
}
catch (AggregateException ae) {
Console.WriteLine("AggregateException caught: " + ae.InnerException);
foreach (var inner in ae.InnerExceptions) {
Console.WriteLine(inner.Message + inner.Source);
}
}
Console.WriteLine("Press any key to exit.");
Console.ReadKey();
cts.Dispose();
}
}
class WorkerWithTimer
{
CancellationTokenSource internalTokenSource = new CancellationTokenSource();
CancellationToken internalToken;
CancellationToken externalToken;
Timer timer;
public WorkerWithTimer()
{
internalTokenSource = new CancellationTokenSource();
internalToken = internalTokenSource.Token;
// A toy cancellation trigger that times out after 3 seconds
// if the user does not press 'c'.
timer = new Timer(new TimerCallback(CancelAfterTimeout), null, 3000, 3000);
}
//<snippet7>
public void DoWork(CancellationToken externalToken)
{
// Create a new token that combines the internal and external tokens.
this.internalToken = internalTokenSource.Token;
this.externalToken = externalToken;
using (CancellationTokenSource linkedCts =
CancellationTokenSource.CreateLinkedTokenSource(internalToken, externalToken))
{
try {
DoWorkInternal(linkedCts.Token);
}
catch (OperationCanceledException) {
if (internalToken.IsCancellationRequested) {
Console.WriteLine("Operation timed out.");
}
else if (externalToken.IsCancellationRequested) {
Console.WriteLine("Cancelling per user request.");
externalToken.ThrowIfCancellationRequested();
}
}
}
}
//</snippet7>
private void DoWorkInternal(CancellationToken token)
{
for (int i = 0; i < 1000; i++)
{
if (token.IsCancellationRequested)
{
// We need to dispose the timer if cancellation
// was requested by the external token.
timer.Dispose();
// Throw the exception.
token.ThrowIfCancellationRequested();
}
// Simulating work.
Thread.SpinWait(7500000);
Console.Write("working... ");
}
}
public void CancelAfterTimeout(object state)
{
Console.WriteLine("\r\nTimer fired.");
internalTokenSource.Cancel();
timer.Dispose();
}
}
//</snippet13>