C# 如何取消任务但等待任务完成?
我有一个线程任务,它在循环中执行一些操作:C# 如何取消任务但等待任务完成?,c#,.net,multithreading,task-parallel-library,C#,.net,Multithreading,Task Parallel Library,我有一个线程任务,它在循环中执行一些操作: static void TaskAction(CancellationToken ct) { while (SomeCondition()) { DoSomeSeriousJob(); ct.ThrowIfCancellationRequested(); } } static void DoSomeSeriousJob() { Console.WriteLine("Serious job
static void TaskAction(CancellationToken ct)
{
while (SomeCondition())
{
DoSomeSeriousJob();
ct.ThrowIfCancellationRequested();
}
}
static void DoSomeSeriousJob()
{
Console.WriteLine("Serious job started");
Thread.Sleep(5000);
Console.WriteLine("Serious job done");
}
我启动它,然后在一段时间后取消:
var cts = new CancellationTokenSource();
var task = Task.Factory.StartNew(() => TaskAction(cts.Token), cts.Token);
Thread.Sleep(1000);
cts.Cancel();
这个操作必须正确完成,我不想打断它。但是我想向我的任务发送一个取消请求,并等待它正确地完成(我的意思是它到达代码中的某个点)。
我尝试了以下方法:
1.等待(取消令牌ct)
在这种情况下,程序立即从Wait()
返回。任务将继续运行,直到通过wifcancellationrequested(),但如果主线程退出,任务也会中断
2.等等
在这里,主线程等待完成,但在最后,aggregateeexception
随着InnerException
=taskcancelledeexception
(而不是operationcancelledeexception
)上升
3.选中IsCancellationRequested(),无异常
在这种情况下,不会出现异常,但任务最终会获得状态RanToCompletion
。当SomeCodition()
开始返回false时,这与正确完成没有区别
所有这些问题都有简单的解决方法,但我想知道,可能我遗漏了什么?有谁能给我提供更好的解决方案吗?如果您想等待任务同步完成(或取消),可以尝试以下方法:
cts.Cancel();
Task.Run(async () => {
try {
await task;
}
catch (OperationCanceledException ex) {
// ...
}
).Wait();
因此,您可以直接捕获OperationCanceledException,而不是捕获AggregateException
编辑:
等待(Caneclationtoken)
这种方法无法达到这个目的。
声明:
等待任务完成执行。如果在任务完成之前取消了取消令牌,则等待将终止
等待()
您可以使用这种方法,但正如您所看到的,您应该期望AggregateException而不是OperationCanceledException。它也在方法的第1部分中指定
AggregateException.InnerException集合包含TaskCanceledException对象
所以在这种方法中,为了确保操作被取消,您可以检查内部expection是否包含TaskCanceledException
检查IsCancellationRequested(),无异常
通过这种方式,很明显没有抛出异常,并且您无法确定操作是否已取消
如果不想同步等待,则一切都会按预期进行:
cts.Cancel();
try {
await task;
}
catch (OperationCanceledException ex) {
// ...
}
试试这个:
try
{
task.GetAwaiter().GetResult();
}
catch (OperationCanceledException)
{
Console.WriteLine("Task cancelled");
}
您将获得一个
OperationCanceledException
,它不会被AggregateException
包装。如果您将取消令牌传递给Wait
,它将取消等待。如果要等待任务完成,请不要将令牌传递给Wait
。Re 2,TaskCanceledException
派生自OperationCanceledException
。如果您使用了Wait
而不是Wait
,那么aggregateeexception
将被打开,您可以捕获InnerException
。juharr,这是我的案例1。如果不等待,调用Wait(ct)
有什么用?明白了。如果令牌被取消,它将等待完成或引发OperationCancelledException
,如果令牌被取消,它将不带参数地等待完成并引发AggregateException
。在情况3中,如果您在观察到已请求取消后离开操作,你仍然认为这个方法已经完成了吗?要区分优雅的执行和取消的执行,可以使用CancellationToken.ThrowIfCancellationRequested
。没有我想要的那么漂亮,但很有趣:)是的,漂亮的方式是异步等待。它可能会工作,但原因不明,声明“此方法旨在供编译器使用,而不是在应用程序代码中使用。“@MehrzadChehraz,MSDN文档也有其不完善之处和含沙射影。这种方法被广泛使用,而且不会有任何进展,因为它是@MehrzadChehraz的一部分。至于您的方法,Task.Run
显然是多余的。您最好只执行(newfunc(async()=>{…}))()。等待()代码>
cts.Cancel();
Task.Run(async () => {
try {
await task;
}
catch (OperationCanceledException ex) {
// ...
}
).Wait();
cts.Cancel();
try {
await task;
}
catch (OperationCanceledException ex) {
// ...
}
try
{
task.GetAwaiter().GetResult();
}
catch (OperationCanceledException)
{
Console.WriteLine("Task cancelled");
}