Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

.Continue starts before task is completed

I have the following code in C#, VS2012, WPF 4.5. My expectation would be that, .ContinueWith will be executed after the task has finished completely (that's a continuation's whole purpose, isn't it?).

This should result in a value of 2 in finalResult.

int myTestInt = 0;

Task task = Task.Factory.StartNew(async () =>
{
   myTestInt = 1;
   await Task.Delay(TimeSpan.FromSeconds(6));
   myTestInt = 2;

}).ContinueWith(_ =>
   {
      int finalResult = myTestInt;
   });

In fact, finalResult is assigned a value of 1 instead. So it seems like the continuation is started on the await statement already.

Is this the intended behaviour? Am I missing something here? Can't I rely on ContinueWithto start after a task has completely finished?

Update:

Justin's answer just inspired me to check the following:

int myTestInt = 0;
Task task=Task.Factory.StartNew(async () =>
{
   myTestInt = 1;
   await Task.Delay(TimeSpan.FromSeconds(6));
   myTestInt = 2;
});

task.Wait();
int result2 = myTestInt;

finalResult is still set to 1. Is there no way to reliably wait for a task that contains awaits to complete?

like image 703
Frank im Wald Avatar asked Nov 08 '12 08:11

Frank im Wald


People also ask

Does Task Whenany start the tasks?

Task. WhenAll doesn't start tasks. The general pattern is that methods that return a Task , return a hot Task .

How do I wait until Task is finished in C#?

C# wait is called that as it waits for the task to finish its execution. Beginners will learn about Wait (TimeSpan), Wait (CancellationToken), Wait (Int32), Wait (Int32, CancellationToken), and Wait for overloads in this tutorial.

What is a continuation Task?

A continuation task (also known just as a continuation) is an asynchronous task that's invoked by another task, known as the antecedent, when the antecedent finishes.

What does calling Task ContinueWith() Do?

ContinueWith(Action<Task,Object>, Object, TaskScheduler)Creates a continuation that receives caller-supplied state information and executes asynchronously when the target Task completes.


1 Answers

When you pass an async delegate to Task.Factory.StartNew, the returned Task only represents the first portion of that delegate (up until the time it awaits something that is not already completed).

However, if you pass an async delegate to the new Task.Run method (which was included for this reason), the returned Task represents the entire delegate. So you can use ContinueWith as you expect. (Although await is usually a better option than ContinueWith).

For more information on StartNew vs Run, see Stephen Toub's post on the topic.

like image 152
Stephen Cleary Avatar answered Oct 20 '22 11:10

Stephen Cleary