How to propagate a Task's Canceled status to a continuation task

淺唱寂寞╮ 提交于 2019-12-07 10:48:43

问题


I am using the Task Parallel Library in my application. I have a Task (let's call it "DoSomething") which may be canceled. Whether the task is faulted, canceled, or completes successfully, I have a continuation attached to that task which performs some cleanup.

In the code that launches this task, I want to return a Task object whose status (faulted, canceled, ran to completion) reflects the status of the DoSomething task, however it's important that this task I return not reflect this status until the continuation task executes.

Here's an example:

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?
}

I could use a TaskCompletionSource, but that seems kludgy. Any other ideas?


回答1:


I think that TaskCompletionSource is actually ideal for this scenario. I.e. you are trying to return a Task as a signal of completion of your work, but manually control when and how that task reports its status. You could easily hide the boiler plate required for this with an extension method like this:

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;
}

and call it like this:

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

The only real caveat is that you can't do this with plain old Task since there is no non-generic TaskCompletionSource.



来源:https://stackoverflow.com/questions/4799011/how-to-propagate-a-tasks-canceled-status-to-a-continuation-task

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!