gpt4 book ai didi

c# - 任务取消和任务继续选项

转载 作者:太空狗 更新时间:2023-10-30 00:19:55 25 4
gpt4 key购买 nike

我昨天刚接触到 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();
}
}

我的worker函数如下:

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 的 Continuation 运行,而不是 TaskContinuationOptions.OnlyOnCanceled。

显然我没有正确地做到这一点。

编辑:

进一步阅读后,我发现一条评论指出:

“catch (OperationCanceledException) {} 会将任务的状态设置为 RanToCompletion,而不是已取消”

因此删除 catch (OperationCanceledException) {} 允许将任务的状态设置为已取消,但程序会在 tokenSource.Token.ThrowIfCancellationRequested() 上中断;但如果我继续休息,则使用 TaskContinuationOptions.OnlyOnCanceled 的延续任务会运行,这很好。

但是如何在不允许程序中断的情况下调用 tokenSource.Token.ThrowIfCancellationRequested(),同时允许将任务状态设置为已取消?

最佳答案

就调试器和防止调试器中断所需的选项而言,以上评论是正确的。然而,下面应该给你一个更好的例子,说明如何使用延续,以及如何处理从这些延续中的任务抛出的异常......

continuation 可以通过先行任务的 exception 属性查明先行 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 block 中等待任务,要么查询任务的 Resulttry/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);
}

希望这对您有所帮助。

关于c# - 任务取消和任务继续选项,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15605860/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com