【问题标题】:How to propagate a Task's Canceled status to a continuation task如何将任务的已取消状态传播到继续任务
【发布时间】:2011-01-25 21:24:17
【问题描述】:

我在我的应用程序中使用任务并行库。我有一个可能被取消的任务(我们称之为“DoSomething”)。无论任务是故障、取消还是成功完成,我都有一个附加到该任务的延续,它执行一些清理。

在启动此任务的代码中,我想返回一个 Task 对象,其状态(故障、取消、运行至完成)反映 DoSomething 任务的状态,但重要的是,我返回的此任务不反映此状态,直到继续任务执行。

这是一个例子:

public Task Start(CancellationToken token)
{
    var doSomethingTask = Task.Factory.StartNew(DoSomething
                                                , token);

    var continuationTask = doSomethingTask.ContinueWith
                (
                 (antecedent) =>
                     {
                         if (antecedent.IsFaulted || antecedent.IsCanceled)
                         {
                             //Do failure-specific cleanup
                         }

   //Do general cleanup without regard to failure or success
                      }
                 );

//TODO: How do I return a Task obj which Status reflect the status of doSomethingTask,
//but will not transition to that status until continuationTask completes?
}

我可以使用 TaskCompletionSource,但这看起来很笨拙。还有其他想法吗?

【问题讨论】:

  • 发布了答案,但出现了问题。正在研究一个更正确的解决方案,我应该很快就会有。
  • 好吧...提问时间:你需要在返回的任务上等待()吗?
  • 是的。返回的任务需要反映原始任务的状态,包括阻塞直到该任务完成执行。

标签: c# c#-4.0 .net-4.0 task-parallel-library


【解决方案1】:

我认为TaskCompletionSource 实际上非常适合这种情况。 IE。您试图返回 Task 作为工作完成的信号,但手动控制该任务何时以及如何报告其状态。您可以使用如下扩展方法轻松隐藏所需的样板:

public static Task<T> WithCleanup<T>(this Task<T> t, Action<Task<T>> cleanup) {
    var cleanupTask = t.ContinueWith(cleanup);
    var completion = new TaskCompletionSource<T>();
    cleanupTask.ContinueWith(_ => {
        if(t.IsCanceled) {
            completion.SetCanceled();
        } else if(t.IsFaulted) {
            completion.SetException(t.Exception);
        } else {
            completion.SetResult(t.Result);
        }
    });
    return completion.Task;
}

然后这样称呼它:

var doSomethingTask = Task.Factory
  .StartNew<object>(DoSomething, token)
  .WithCleanup(Cleanup);

唯一真正需要注意的是,您不能对普通的旧 Task 执行此操作,因为没有非泛型 TaskCompletionSource

【讨论】:

  • 您可以将通用 TCS 用于非通用情况,因为 Task&lt;T&gt; 继承自 Task
猜你喜欢
  • 2020-01-29
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-01-01
  • 2012-03-29
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多