ColdTask implementation for Windows 8

Tasks in Windows 8 are used all over the place – they are a really great way of getting things done asynchronously. Sometimes though, you find yourself wanting to change the way these tasks execute.

Most .NET tasks are “hot” – meaning they run when they are created or as soon as they can run. The two exceptions I could find were new Task(Action) and TaskCompletionSource. image

Most tasks people use in Windows 8 are consumed via the await keyword, applied to a method or task. These are hot as well.

What if you wanted to create a task where you controlled the start of which? This capability is not usually required – so far I have only encountered the need when doing locking. The problems you may run into when mixing locks and tasks are:

  1. You cannot await a task from within a lock (nor should you be able to).
  2. If you call the task from within the lock (so you can await it outside of the lock), the code will start running – if that code does something that should not happen inside the lock, you are in a bind.

There are a number of suggestions for solutions that I saw, but I have not seen an end to end class that does it, so here goes..

ColdTask and ColdTask<T> classes

These two classes let you create a cold task from an existing task. As an example, say you have a task you want running at most once in your system at any given time. Here’s a simple example of how to create the cold task:

ColdTask<string> coldTask = null;
coldTask = new ColdTask<string>(() => RunAsync());
// Can call coldTask.GetTask() to get the task here, if needed.

The important bit here is that ColdTask() takes a delegate that creates the task, so that it can defer this to when the caller would want to use it – in this case, it simply calls an async function called RunAsync().

That’s the preparation part – at a later time, you want to start and await the task:

await coldTask.Start();

That’s it – that’s all it takes.

How does it work?

The class itself is pretty simple. First off, fields and constructor:

public class ColdTask<TResult>
{
private Func<Task<TResult>> m_factory;
private Task m_bootstrapper;
private Task<TResult> m_task;



public ColdTask(Func<Task<TResult>> factory)
{
m_factory = factory;
m_bootstrapper = new Task(() => { });
}

m_bootstrapper is the task that will “halt” the execution so that it can later be “resumed”. In essense, we are using that empty Action delegate as a suspend mechanism.

Next, we have the implementation of GetTask() which returns the suspended task:

public Task<TResult> GetTask()
{
if (m_task == null)
{
m_task = InternalGetTask();
}

return m_task;
}

private async Task<TResult> InternalGetTask()
{
await m_bootstrapper;
return await m_factory();
}

InternalGetTask() awaits the bootstrapper and then calls the delegate passed in the constructor and awaits that. Since the bootstrapper is not started yet, you can see how it acts like a “suspend” mechanism.

GetTask() caches the task so that it won’t get created twice if it’s called.

Finally, Start does just that – starts the suspended empty task:

public Task<TResult> Start()
{
m_bootstrapper.Start();
return GetTask();
}

And that’s it pretty much!

You can download the cs file containing this class (as well as a non-generic version), you can download it here.

Advertisements
This entry was posted in Dev, Windows8 and tagged , , , , , , . Bookmark the permalink.

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 )

Twitter picture

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

Facebook photo

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

Google+ photo

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

Connecting to %s