Skip to content

Instantly share code, notes, and snippets.

@StephenCleary
Last active February 4, 2024 12:29
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save StephenCleary/37d95619f7803f444d3d to your computer and use it in GitHub Desktop.
Save StephenCleary/37d95619f7803f444d3d to your computer and use it in GitHub Desktop.
How StartNew responds to CancellationToken
using System;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.VisualStudio.TestTools.UnitTesting;
[TestClass]
public class StartNewCancellationTokenUnitTests
{
[TestMethod]
public void CancellationTokenPassedToStartNew_CancelsTaskWithTaskCanceledException()
{
var cts = new CancellationTokenSource();
cts.Cancel();
var task = Task.Factory.StartNew(() => { }, cts.Token);
TaskCanceledException exception = null;
try
{
task.Wait();
}
catch (AggregateException ex)
{
// TaskCanceledException derives from OperationCanceledException
exception = ex.InnerException as TaskCanceledException;
}
Assert.IsTrue(task.IsCanceled);
Assert.IsNotNull(exception);
Assert.AreEqual(cts.Token, exception.CancellationToken);
}
[TestMethod]
public void CancellationTokenObservedByDelegate_FaultsTaskWithOperationCanceledException()
{
var cts = new CancellationTokenSource();
cts.Cancel();
var task = Task.Factory.StartNew(() => { cts.Token.ThrowIfCancellationRequested(); });
OperationCanceledException exception = null;
try
{
task.Wait();
}
catch (AggregateException ex)
{
exception = ex.InnerException as OperationCanceledException;
}
Assert.IsTrue(task.IsFaulted);
Assert.IsNotNull(exception);
Assert.AreEqual(cts.Token, exception.CancellationToken);
}
[TestMethod]
public void CancellationTokenObservedAndPassed_CancelsTaskWithTaskCanceledException()
{
var cts = new CancellationTokenSource();
var taskReady = new ManualResetEvent(false);
var task = Task.Factory.StartNew(() =>
{
taskReady.Set();
while (true)
cts.Token.ThrowIfCancellationRequested();
}, cts.Token);
taskReady.WaitOne();
cts.Cancel();
OperationCanceledException exception = null;
try
{
task.Wait();
}
catch (AggregateException ex)
{
// TaskCanceledException derives from OperationCanceledException
exception = ex.InnerException as TaskCanceledException;
}
Assert.IsTrue(task.IsCanceled);
Assert.IsNotNull(exception);
Assert.AreEqual(cts.Token, exception.CancellationToken);
}
}
@jmonasterio
Copy link

So helpful. Would be nice if this were part of the Microsofts docs.

@CrispyDrone
Copy link

Might be interesting to add another test that demonstrates the user delegate never executes if the token is already in the cancellation requested state before the task is created.

@StephenCleary
Copy link
Author

👍 Good point. Yes, the delegate is never actually executed if it is cancelled before it starts. :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment