Parallel.ForEach ループを実装して何らかの作業を行っていましたが、キャンセルを処理していると思っていたときに、未処理の例外が原因で問題が発生しました。
問題を把握するために、winform で簡単なテスト設定を行いました。開始ボタン、キャンセル ボタン、出力用のラベルがあります。
コード:
public partial class Form1 : Form
{
CancellationTokenSource cts = new CancellationTokenSource();
public Form1()
{
InitializeComponent();
}
private async void button1_Click(object sender, EventArgs e)
{
output.Text = "Running";
try
{
var runTask = Task<string>.Factory.StartNew(() => Run());
await runTask;
this.output.Text = runTask.Result;
}
catch(Exception ex)
{
throw ex;
}
}
private string Run()
{
int useThreads = Environment.ProcessorCount - 2 < 1 ? 1 : Environment.ProcessorCount - 2;
ParallelOptions options = new ParallelOptions() { MaxDegreeOfParallelism = useThreads, CancellationToken = cts.Token };
options.CancellationToken.Register(() => ActionOnCancel());
List<int> somelist =new List<int>();
for(int i = 0; i < 100; i++)
somelist.Add(i);
Parallel.ForEach(somelist, options, (row, loopstate) =>
{
if(loopstate.ShouldExitCurrentIteration || loopstate.IsExceptional)
loopstate.Stop();
Thread.Sleep(1000);
});
return "Done";
}
private void ActionOnCancel()
{
output.Text= "Cancelled";
}
private void button2_Click(object sender, EventArgs e)
{
cts.Cancel();
}
プログラムを実行してキャンセル ボタンを押すと (button2_Click をトリガーするため)、次のエラーが発生し続けます。
タイプ 'System.OperationCanceledException' の例外が mscorlib.dll で発生しましたが、ユーザー コードで処理されませんでした
追加情報: 操作はキャンセルされました。
この例外のハンドラがあれば、プログラムは安全に続行できます。
また、デバッガーは Parallel.ForEach セクションを強調表示します。しかし、なぜ???CancellationToken を介してキャンセルを正しく処理したと思います。
ex の例外メッセージでは、明確な説明が得られません:「{"操作がキャンセルされました。"}」ええと...ええ....それが意図されていました...
私は何を見落としていますか?よろしく、
マティス