The Task Parallel Library Sampler – Part 12: Cancelling Threads with the CancellationTokenSource – The Code

Previous Post in this series:
Part 11: Cancelling Threads with the CancellationTokenSource – The MVVM

So now that we’ve covered the MVVM, which you saw was pretty trivial to implement, let’s cover the actual sample.

CancellationSample.Run

public override void Run(System.Drawing.Bitmap bmp = null, Action<string> UpdateLog = null)
{
	Stopwatch s = new Stopwatch();
	s.Start();

	IsRunning = true;

	CancellationTokenSource = new CancellationTokenSource();
	CancellationTokenSource.Token.Register(() => { IsRunning = false; });

	var options = new ParallelOptions { CancellationToken = CancellationTokenSource.Token };
	try
	{
		Parallel.ForEach(WhileTrue(), options, i =>
		{
			while (!options.CancellationToken.IsCancellationRequested)
			{
				UpdateLog("Sleeping in Cancellation Sample at " + i);
				Thread.Sleep(ran.Next(1000));
			}
		});
	}
	catch (OperationCanceledException)
	{
		UpdateLog("Operation has been cancelled."); ;
	}

	s.Stop();
	RunTime = s.Elapsed;
}

public static IEnumerable<int> WhileTrue()
{
	for (int i = 0; ; i++)
		yield return i;
}

We start by instantiating the CancellationTokenSource that holds our token. We have to do this for each run or else the token is already cancelled and the threads in the Parallel.ForEach won’t spawn.

Line 9 is pretty interesting. We’re registering a call-back to fire when the token gets cancelled. Here we set “IsRunning” to false but you can put any delegate here. This way when whatever code external to us cancels the token then we can handle the IsRunning.

Next we instantiate a ParallelOptions, setting the CancellationToken to the Token of the CancellationTokenSource.

The most important thing with all this is to note that cancelling the CancellationTokenSource doesn’t stop any threads, it just prevents more threads from being spawned. Because of this we have to check in our while loop if the CancellationToken has been cancelled and if it has been then stop. When canceling the CancellationTokenSource this will cause an OperationCanceledException to be thrown. This way you can handle if there is any clean-up that needs to happen if your Parallel.For and .ForEach may not have completed. In our case I’m using a “WhileTrue” that just goes on infinitely.

Up next I’ll go into async/await.

Thanks,
Brian

Leave a Reply