任务取消和TaskContinuationOptions

任务取消和TaskContinuationOptions

本文介绍了任务取消和TaskContinuationOptions的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我只是介绍了任务(TPL)昨天,所以我想,以发展的如何使用它们的理解做一个小样本项目。

I was just introduced to Tasks (TPL) yesterday, and so I tried to do a little sample project in order to develop an understanding of how to use them.

我的示例项目被设定与开始递增进度启动按钮。第二个按钮,删除该任务。报告的文本框时使用TaskContinuationOptions.OnlyOnRanToCompletion延续被调用,而当使用TaskContinuationOptions.OnlyOnCanceled延续叫做报告的文本框。

My sample project is setup with a start button that begins incrementing a progressbar. A second button to cancel the task. A text box to report when the continuation using the TaskContinuationOptions.OnlyOnRanToCompletion is called, and a text box to report when the continuation using the TaskContinuationOptions.OnlyOnCanceled is called.

我可以创建并执行任务,但在某种程度上,让与TaskContinuationOptions.OnlyOnCanceled标志火灾延续取消它,一直是一个难题。

I can create and execute a Task, but canceling it in a way that lets a continuation with the TaskContinuationOptions.OnlyOnCanceled flag to fire, has been a problem.

我创建的任务如下:

private void StartTask()
{
    CancellationTokenSource tokenSource = new CancellationTokenSource();
    CancellationToken token = tokenSource.Token;

    Task task = null;
    task = Task.Factory.StartNew(() => DoWork(tokenSource), tokenSource.Token);

    //A list<CancellationTokenSource> so that I can cancel the task when clicking a button on the UI Thread.
    MyTasks.Add(tokenSource);

    Task completed = task.ContinueWith(result => TaskCompleted(), TaskContinuationOptions.OnlyOnRanToCompletion);
    Task canceled = task.ContinueWith(result => TaskCanceled(), TaskContinuationOptions.OnlyOnCanceled);
}



我取消任务如下:

I cancel the task as follows:

private void CancelTasks()
{
    foreach (CancellationTokenSource tokenSource in MyTasks)
    {
        tokenSource.Cancel();
    }
}



我的工人功​​能如下:

My worker function is as follows:

private void DoWork(CancellationTokenSource tokenSource)
{
    if (progressBar1.InvokeRequired)
    {
        progressBar1.Invoke(new Action(() => DoWork(tokenSource)));
        return;
    }

    try
    {
        bool dowork = true;
        while (dowork)
        {
            tokenSource.Token.ThrowIfCancellationRequested();

            if (progressBar1.Value == progressBar1.Maximum)
            {
                dowork = false;
            }
            Thread.Sleep(1000);
            progressBar1.PerformStep();
            Application.DoEvents();
        }
        countCompleted++;
    }
    catch (OperationCanceledException)
    {
    }
}

在其他职位,我已阅读,它已被认为tokenSource.Token.ThrowIfCancellationRequested()是设置由TaskContinuationOptions.OnlyOnCanceled评估的条件。

In other posts that I have read, it has been suggested that tokenSource.Token.ThrowIfCancellationRequested() is what sets the condition evaluated by the TaskContinuationOptions.OnlyOnCanceled.

中,我所看到的例子没有包括使用的:

None of the examples that I have seen include the use of the:

catch (OperationCanceledException)
{
}

然而,如果没有它的程序停止时,我打电话tokenSource.Cancel( );

However, without it the programs stops when i call the tokenSource.Cancel();

既然这样,当我做调用tokenSource.Cancel(),续修与TaskContinuationOptions.OnlyOnRanToCompletion运行,而不是TaskContinuationOptions.OnlyOnCanceled。

As it stands, when I do call the tokenSource.Cancel(), the Continuation with the TaskContinuationOptions.OnlyOnRanToCompletion runs, instead of the TaskContinuationOptions.OnlyOnCanceled.

显然我没有正确地做这个

Clearly I'm not doing this correctly.

修改

做一些进一步的阅读中,我发现,规定的评价是:

Doing some further reading, I found a comment that states that:

捕获(OperationCanceledException){}将设置任务的地位RanToCompletion,而不是作为取消

"catch (OperationCanceledException) {} will set the task's status as RanToCompletion, not as Canceled"

因此,移除捕获(OperationCanceledException){}允许该任务的状态被设置为取消,但对tokenSource.Token的程序中断.ThrowIfCancellationRequested();但如果我再继续通过休息,与TaskContinuationOptions.OnlyOnCanceled延续任务运行,这是很好的。

So removing the catch (OperationCanceledException) {} allows the task's status to to be set to canceled, but the program breaks on the tokenSource.Token.ThrowIfCancellationRequested(); but if I then continue through the break, the continuation task with the TaskContinuationOptions.OnlyOnCanceled runs, which is good.

但我怎么叫tokenSource.Token.ThrowIfCancellationRequested()没有允许程序断裂,同时允许任务状态设置为已取消?

But how do I call tokenSource.Token.ThrowIfCancellationRequested() without allowing the program to break and while allowing the task status to be set to Canceled?

推荐答案

上面的评论是项正确的调试,并防止调试断裂所需的选项。但是,以下应该给你如何使用延续乃至如何处理那些延续......

The comments above are correct in terms of the debugger and the options required to prevent the debugger breaking. However, the following should give you a better example of how to use continuations and indeed how to handle exceptions thrown from tasks within those continuations...

一个延续可以找到如果一个异常被抛出的前因工作的先行任务的异常属性。下面将打印的NullReferenceException 的结果到控制台

A continuation can find out if an exception was thrown by the antecedent Task by the antecedent task's exception property. The following prints the results of a NullReferenceException to the console

Task task1 = Task.Factory.StartNew (() => { throw null; });
Task task2 = task1.ContinueWith (ant => Console.Write(ant.Exception());

如果任务1 抛出一个异常,而这个异常没有捕获/继续问,它被认为是未处理和应用死亡。有了延续它足以确立通过状态关键字

If task1 throws an exception and this exception is not captured/queried by the continuation it is considered unhandled and the application dies. With continuations it is enough to establish the result of the task via the Status keyword

asyncTask.ContinueWith(task =>
{
    // Check task status.
    switch (task.Status)
    {
        // Handle any exceptions to prevent UnobservedTaskException.
        case TaskStatus.RanToCompletion:
            if (asyncTask.Result)
            {
                // Do stuff...
            }
            break;
        case TaskStatus.Faulted:
            if (task.Exception != null)
                mainForm.progressRightLabelText = task.Exception.InnerException.Message;
            else
                mainForm.progressRightLabelText = "Operation failed!";
        default:
            break;
    }
}

如果你不使用你的延续要么必须等待中的任务尝试 / 块或查询任务的结果尝试 /

If you don't use continuations you either have to wait on the task in a try/catch block or query a task's Result in a try/catch block

int x = 0;
Task<int> task = Task.Factory.StartNew (() => 7 / x);
try
{
    task.Wait();
    // OR.
    int result = task.Result;
}
catch (AggregateException aggEx)
{
    Console.WriteLine(aggEx.InnerException.Message);
}



希望这有助于。

Hope this helps.

这篇关于任务取消和TaskContinuationOptions的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

09-02 04:26