Continuation tasks in .NET TPL: any task in an array continued by a single task

Tasks in .NET TPL make it easy to assign tasks that should run upon the completion of a certain task.

In this post we saw how to create many tasks followed by a single continuation task that runs after all the antecedents have completed. We can also have the following scenario: a group of antecedent tasks are started and a single continuation task will be scheduled to run when the first task in the array of antecedent tasks has completed. You use the ContinueWhenAny() method to achieve this.

Make sure to read the post referred to above as ContinueWhenAll() and ContinueWhenAny() are very similar. Read especially the section on return values as it also applies to this post: just replace “ContinueWhenAll” with “ContinueWhenAny” in the examples. Also, read this post to apply a condition when the continuation task should be scheduled.

In the below example we’ll create a range of tasks that all return an integer: the number of milliseconds they were put to sleep. A CancellationToken object is used to introduce a random pause whose length is randomised between 100 and 1000 milliseconds. The access to the Random object is synchronised by a synchronisation primitive.

We declare a couple of elements first:

Task<int>[] motherTasks = new Task<int>[10];
CancellationTokenSource cancellationTokenSource = new CancellationTokenSource();

Random random = new Random();
Object syncPrimitive = new object();

The task array is filled and each task is started and returns an integer:

for (int i = 0; i < 10; i++)
{
	motherTasks[i] = Task.Factory.StartNew<int>(() =>
	{
		int taskSleepInterval;
		lock (syncPrimitive)
		{
			taskSleepInterval = random.Next(100, 1000);
		}
		cancellationTokenSource.Token.WaitHandle.WaitOne(taskSleepInterval);
		cancellationTokenSource.Token.ThrowIfCancellationRequested();
		return taskSleepInterval;
	}, cancellationTokenSource.Token);
}

Next we declare the continuation task:

Task continuationTask = Task.Factory.ContinueWhenAny<int>(motherTasks,
	(Task<int> antecedent) =>
	{
		Console.WriteLine("The first task slept for {0} milliseconds",
			antecedent.Result);
	});

The continuation task will be scheduled to run as soon as the first task in the antecedent task array has completed.

We wait for the continuation task to finish and then cancel the token source:

continuationTask.Wait();
cancellationTokenSource.Cancel();

Run the code and you’ll see that the continuation task reports the result from the first task.

View the list of posts on the Task Parallel Library here.

About Andras Nemes
I'm a .NET/Java developer living and working in Stockholm, Sweden.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

ultimatemindsettoday

A great WordPress.com site

Elliot Balynn's Blog

A directory of wonderful thoughts

HarsH ReaLiTy

A Good Blog is Hard to Find

Softwarearchitektur in der Praxis

Wissenswertes zu Webentwicklung, Domain-Driven Design und Microservices

Technology Talks

on Microsoft technologies, Web, Android and others

Software Engineering

Web development

Disparate Opinions

Various tidbits

chsakell's Blog

WEB APPLICATION DEVELOPMENT TUTORIALS WITH OPEN-SOURCE PROJECTS

Once Upon a Camayoc

Bite-size insight on Cyber Security for the not too technical.

Guru N Guns's

OneSolution To dOTnET.

Johnny Zraiby

Measuring programming progress by lines of code is like measuring aircraft building progress by weight.

%d bloggers like this: