繁体   English   中英

如何取消任务,但要等到完成?

[英]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();

此操作必须正确完成,我不想中断它。 但是我想向我的任务发送一个取消请求, 然后等待它正确完成 (这意味着它到达了代码中的某个点)。 我尝试了以下方法:

1.等待(CancellationToken ct)

try
{
    task.Wait(cts.Token);
}
catch (OperationCanceledException)
{
    Console.WriteLine("Task cancelled");
}
// Must be joined here.

在这种情况下,程序立即从Wait()返回。 任务将继续运行,直到ThrowIfCancellationRequested()但是如果主线程退出,任务也会被中断。

2. Wait()

try
{
    task.Wait();
}
catch (OperationCanceledException)
{
    Console.WriteLine("Task cancelled");
}
catch (Exception ex)
{
    Console.WriteLine(ex.ToString());
}

在这里,主线程等待完成,但是最后, InnerException = TaskCancelledException (不是OperationCancelledExceptionTaskCancelledException AggregateException

3.检查IsCancellationRequested(),没有异常

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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM