Multiple Task Continuation

2019-07-23 22:58发布

问题:

I would like to understand this scenario a little clearer:

Consider the following code:

frmProgressAsync prog = new frmProgressAsync(true);
TaskWithProgress t = new TaskWithProgress("Smoothing CP", true);
t.Task = A.ShowMovingAverage(tension,t.Progress)
       .ContinueWith(prev =>
           {
               t.ProgressInformation.Report("Smoothing FG");
               B.ShowMovingAverage(tension, t.Progress);
           });
await prog.RunAsync(t);

I have two tasks I wish to run A.ShowMovingAverage and B.ShowMovingAverage. Both return a Task.

In the prog.RunAsync() method, I have the following:

    public virtual Task RunAsync(TaskWithProgress task)
    {
        Show();
        TaskIsRunning();
        task.ContinueWith(Close(), CancellationToken.None, TaskContinuationOptions.OnlyOnRanToCompletion, this._Scheduler);
        return task.Task;
    }

So effectively I have three tasks, to run in turn one after the previous is complete.

Now my issue is in some cases the first task completes virtually immediately. When the call to prog.RunAsync() is made, and the final continuation is appended to the task, it immediately runs, closing the form.

I can see if I break on the last ContinueWith() call, the task status is RanToCompletion, but I am kind of expecting the continuation to reset this back to in progress.

Could someone please explain this behavior a little more cleanly? And provide a potential solution so that all the tasks (continuations) complete before the final continuation?

回答1:

Tasks only complete one time. When you attach a continuation, you are creating a new task that starts when the antecedent task completes. So, I believe the problem you're seeing is that RunAsync is attaching the Close continuation but not doing anything with the continuation task; consider task.Task = task.ContinueWith(Close(), ...).

However, I recommend that you use await instead of ContinueWith. I find that usually clarifies the code and makes it easier to understand.

frmProgressAsync prog = new frmProgressAsync(true);
TaskWithProgress t = new TaskWithProgress("Smoothing CP", true);
t.Task = ShowMovingAveragesAsync(A, B, tension, t.Progress);
await prog.RunAsync(t);

private async Task ShowMovingAveragesAsync(TA A, TA B, TT tession, IProgress<string> progress)
{
  progress.Report("Smoothing FG");
  await A.ShowMovingAverageAsync(tension, progress);
  progress.Report("Smoothing FG");
  await B.ShowMovingAverageAsync(tension, progress);
}

public virtual async Task RunAsync(TaskWithProgress task)
{
  Show();
  TaskIsRunning();
  await task;
  Close();
}