发生了'System.OperationCanceledException'类型的异常

时间:2012-12-14 15:34:39

标签: c# exception cancellation parallel.foreach

我正在实现一个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)时,我继续收到此错误:

  

mscorlib.dll中出现“System.OperationCanceledException”类型的异常,但未在用户代码中处理

     

其他信息:操作已取消。

     

如果存在此异常的处理程序,则可以安全地继续该程序。

调试器突出显示Parallel.ForEach部分。但为什么???我以为我通过CancellationToken处理了取消错误。

ex中的异常消息并没有给我任何清晰的说明:“{”操作被取消了。“}”呃......是的......这是意图......

我在俯瞰什么? 的问候,

Matthijs

2 个答案:

答案 0 :(得分:8)

始终抛出此异常。如果在CancellationTokenSource上调用cancel方法,则必须在访问Parallel Tasks时处理OperationCanceledException。

try
{
    Parallel.ForEach(somelist, options, (row, loopstate) =>
    {
        if(loopstate.ShouldExitCurrentIteration || loopstate.IsExceptional)
            loopstate.Stop();

        Thread.Sleep(1000);

    });
}
catch (OperationCanceledException)
{
    // Handle the cancelled Task
}

答案 1 :(得分:1)

CancellationToken.Register()提供了一种方法,可以根据OperationCanceledException将回调添加到取消中,但不会“处理”它。

我建议你在Run()方法中放置一个try / catch块。