[英]How to cancel Task but wait until it finishes?
我有线程任务,可以在循环中执行一些操作:
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();
此操作必须正确完成,我不想中断它。 但是我想向我的任务发送一个取消请求, 然后等待它正确完成 (这意味着它到达了代码中的某个点)。 我尝试了以下方法:
try
{
task.Wait(cts.Token);
}
catch (OperationCanceledException)
{
Console.WriteLine("Task cancelled");
}
// Must be joined here.
在这种情况下,程序立即从Wait()
返回。 任务将继续运行,直到ThrowIfCancellationRequested()
但是如果主线程退出,任务也会被中断。
try
{
task.Wait();
}
catch (OperationCanceledException)
{
Console.WriteLine("Task cancelled");
}
catch (Exception ex)
{
Console.WriteLine(ex.ToString());
}
在这里,主线程等待完成,但是最后, InnerException
= TaskCancelledException
(不是OperationCancelledException
) TaskCancelledException
AggregateException
。
static void TaskAction(CancellationToken ct)
{
while (SomeCondition())
{
DoSomeSeriousJob();
if (ct.IsCancellationRequested)
break;
}
}
// ...
task.Wait();
在这种情况下,不会RanToCompletion
任何异常,但是任务最后将获得状态RanToCompletion
。 当SomeCodition()
开始返回false时,这与正确完成没有SomeCodition()
。
所有这些问题都有简单的解决方法,但我想知道,可能是我缺少了什么吗? 有人可以建议我更好的解决方案吗?
如果要等待任务同步完成(或取消),可以尝试以下操作:
cts.Cancel();
Task.Run(async () => {
try {
await task;
}
catch (OperationCanceledException ex) {
// ...
}
).Wait();
这样您就可以直接捕获OperationCanceledException而不是捕获AggregateException。
编辑:
等待(CanecllationToken)
此方法不适用于该目的。 MSDN声明:
等待任务完成执行。 如果在任务完成之前取消了取消令牌,则等待终止。
等待()
您可以使用这种方法,但是如您所见,应该期望AggregateException而不是OperationCanceledException。 该方法的文档中也指定了它。
AggregateException.InnerExceptions集合包含一个TaskCanceledException对象。
因此,在这种方法中,为了确保操作被取消,您可以检查内部期望是否包含TaskCanceledException。
检查IsCancellationRequested()并且没有异常
这样,很明显不会引发任何异常,并且您无法确定操作是否被取消。
如果您不想同步等待,那么一切都会按预期进行:
cts.Cancel();
try {
await task;
}
catch (OperationCanceledException ex) {
// ...
}
尝试这个:
try
{
task.GetAwaiter().GetResult();
}
catch (OperationCanceledException)
{
Console.WriteLine("Task cancelled");
}
您将获得OperationCanceledException
,并且不会将其与AggregateException
一起包装。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.