Parallel.ForEachを途中でキャンセルする場合、CancellationTokenを使うわけですが、ネット上のサンプルソースにはThrowIfCancellationRequestedメソッドを使うものがあります。しかし、このメソッドは無くても良かったようです。
using System;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
namespace CancelationToken001
{
class Program
{
static void Main(string[] args)
{
var cts = new CancellationTokenSource();
var options = new ParallelOptions()
{
CancellationToken = cts.Token
};
var t = new Task(() =>
{
Thread.Sleep(500);
cts.Cancel();
});
t.Start();
try
{
Parallel.ForEach(ParallelEnumerable.Range(1, 100), options, n =>
{
Console.Write("{0} ", n);
Thread.Sleep(1000);
});
}
catch (OperationCanceledException)
{
Console.WriteLine("Canceled");
}
}
}
}
ThrowIfCancellationRequestedメソッドはForEachメソッドの引数のラムダ式内にあっても構わないように見えますが、実は良くないようです。別スレッドで例外を上げるとキャッチできず、そこで「ハンドルされない例外」扱いされるようです。このソースでもキャンセル例外は上がってきますが、呼び出し側スレッドでキャッチできる例外が上がってくるので大丈夫のようです。