我昨天刚被介绍给任务(TPL),所以我尝试做一个小的示例项目,以便了解如何使用它们。
我的示例项目是使用开始按钮设置的,该按钮开始递增进度条。取消任务的第二个按钮。一个文本框用于报告使用TaskContinuationOptions.OnlyOnRanToCompletion的延续何时调用,另一个文本框用于报告使用TaskContinuationOptions.OnlyOnCanceled的延续何时被调用。
我可以创建和执行一个任务,但取消它的方式允许继续使用TaskContinuationOptions.OnlyOnCanceled标志触发,这是一个问题。
我创建的任务如下:
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);
}我取消这项任务如下:
private void CancelTasks()
{
foreach (CancellationTokenSource tokenSource in MyTasks)
{
tokenSource.Cancel();
}
}我的工作人员职能如下:
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评估的条件。
我所看到的例子中,没有一个包括使用:
catch (OperationCanceledException)
{
}但是,如果没有它,程序将在调用tokenSource.Cancel()时停止;
目前,当我调用tokenSource.Cancel()时,TaskContinuationOptions.OnlyOnRanToCompletion的延续将运行,而不是TaskContinuationOptions.OnlyOnCanceled。
显然我做得不对。
编辑
在进一步阅读时,我发现一条评论说:
"catch (OperationCanceledException) {}将任务的状态设置为RanToCompletion,而不是已取消的状态“
因此,删除catch (OperationCanceledException) {}允许将任务的状态设置为已取消,但程序在OperationCanceledException上中断,但如果我接着继续执行中断,则TaskContinuationOptions.OnlyOnCanceled的延续任务将运行,这很好。
但是,如何调用tokenSource.Token.ThrowIfCancellationRequested(),而不允许程序中断,同时允许将任务状态设置为“取消”?
发布于 2013-03-25 09:38:52
就调试器和防止调试器中断所需的选项而言,上面的注释是正确的。但是,下面将给您提供一个更好的示例,说明如何使用延续,以及如何处理从这些延续中的任务引发的异常.
一个延续可以找出一个异常是否是由前置任务的Task异常属性引发的。下面将NullReferenceException的结果打印到控制台
Task task1 = Task.Factory.StartNew (() => { throw null; });
Task task2 = task1.ContinueWith (ant => Console.Write(ant.Exception());如果task1抛出一个异常,而这个异常没有被延续捕获/查询,那么它就被认为是未处理的,并且应用程序会死掉。有了连续性,就可以通过Status关键字建立任务的结果了。
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;
}
}如果不使用连续,则必须在try/catch块中等待任务,或者在try/catch块中查询任务的Result
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);
}希望这能有所帮助。
https://stackoverflow.com/questions/15605860
复制相似问题