Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Task chaining (wait for the previous task to completed)

var tasks = new List<Task>();

foreach (var guid in guids)
{
    var task = new Task( ...);
    tasks.Add(task);
}

foreach (var task in tasks)
{
    task.Start();
    Task.WaitAll(task);
}

This is run of the UI thread. I need to execute all tasks in tasks variable one after the other. The problem is if I call Task.WaitAll(task), the UI freeze. How can I do the following logic without having the UI freeze?

like image 572
Melursus Avatar asked Jul 25 '12 12:07

Melursus


People also ask

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 is ContinueWith c#?

The ContinueWith function is a method available on the task that allows executing code after the task has finished execution. In simple words it allows continuation. Things to note here is that ContinueWith also returns one Task. That means you can attach ContinueWith one task returned by this method.

How do I run a task in C#?

To start a task in C#, follow any of the below given ways. Use a delegate to start a task. Task t = new Task(delegate { PrintMessage(); }); t. Start();


2 Answers

This is not Task Chaining.

You need to do Task chaining using ContinueWith. Last task would need to update the UI.

Task.Factory.StartNew( () => DoThis())
   .ContinueWith((t1) => DoThat())
   .ContinueWith((t2) => UpdateUi(), 
       TaskScheduler.FromCurrentSynchronizationContext());

Note the last line has TaskScheduler.FromCurrentSynchronizationContext() this will ensure task will run in the synchronization context (UI Thread).

like image 100
Aliostad Avatar answered Oct 19 '22 17:10

Aliostad


The best way is to use the Task Parallel Library (TPL) and Continuations. A continuation not only allows you to create a flow of tasks but also handles your exceptions. This is a great introduction to the TPL. But to give you some idea...

You can start a TPL task using

Task task = Task.Factory.StartNew(() => 
{
    // Do some work here...
});

Now to start a second task when an antecedent task finishes (in error or successfully) you can use the ContinueWith method

Task task1 = Task.Factory.StartNew(() => Console.WriteLine("Antecedant Task"));
Task task2 = task1.ContinueWith(antTask => Console.WriteLine("Continuation..."));

So as soon as task1 completes, fails or is cancelled task2 'fires-up' and starts running. Note that if task1 had completed before reaching the second line of code task2 would be scheduled to execute immediately. The antTask argument passed to the second lambda is a reference to the antecedent task. See this link for more detailed examples...

You can also pass continuations results from the antecedent task

Task.Factory.StartNew<int>(() => 1)
    .ContinueWith(antTask => antTask.Result * 4)
    .ContinueWith(antTask => antTask.Result * 4)
    .ContinueWith(antTask =>Console.WriteLine(antTask.Result * 4)); // Prints 64.

Note. Be sure to read up on exception handling in the first link provided as this can lead a newcomer to TPL astray.

One last thing to look at in particular for what you want is child tasks. Child tasks are those which are created as AttachedToParent. In this case the continuation will not run until all child tasks have completed

TaskCreationOptions atp = TaskCreationOptions.AttachedToParent;
Task.Factory.StartNew(() =>
{
    Task.Factory.StartNew(() => { SomeMethod() }, atp);
    Task.Factory.StartNew(() => { SomeOtherMethod() }, atp); 
}).ContinueWith( cont => { Console.WriteLine("Finished!") });

I hope this helps.

like image 22
MoonKnight Avatar answered Oct 19 '22 16:10

MoonKnight