问题描述
我只是介绍了任务(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的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!