昨天我刚刚被介绍给 Tasks (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,而不是 Canceled”
因此删除 catch (OperationCanceledException) {} 允许将任务的状态设置为已取消,但程序在 tokenSource.Token.ThrowIfCancellationRequested(); 但是如果我继续休息,带有 TaskContinuationOptions.OnlyOnCanceled 的继续任务运行,这很好。
但是我如何调用 tokenSource.Token.ThrowIfCancellationRequested() 而不允许程序中断并且允许将任务状态设置为已取消?