Windows Store Apps: Threads to Tasks

Posted on June 21, 2013

If you’re updating an old .NET code base to a Windows Store app, you may notice that the Thread class is no longer available.  Instead, we have the more sophisticated Task.  If you have a lot of Thread usage in your old code, you may find a re-write of the threading code to be a large task (sorry).

Here’s some code that you can use in place of the missing Thread class. This uses Tasks under the hood:

using System;
using System.Threading;
using System.Threading.Tasks;

namespace WindowsStore.Compatibility
{
	public class Thread
	{
		public Thread(ThreadStart start)
		{
			if (start == null)
				throw new ArgumentNullException("start");
			action = new Action(start);
		}
		public Thread(ParameterizedThreadStart start)
		{
			if (start == null)
				throw new ArgumentNullException("start");
			parameterizedAction =
			 new Action(start);
		}
		
		public void Start()
		{
			t = new Task(ThreadProc, null, cancelTokenSource.Token);
			t.Start();
		}
		public void Start(object o)
		{
			t = new Task(ThreadProc, o, cancelTokenSource.Token);
			t.Start();
		}
		
		public void Join()
		{
			t.Wait();
		}
		public bool Join(int ms)
		{
			return t.Wait(ms);
		}
		
		public void Abort()
		{
			cancelTokenSource.Cancel();
		}
		
		public static void Sleep(int ms)
		{
			new ManualResetEvent(false).WaitOne(ms);
		}
		public static void Sleep(TimeSpan ts)
		{
			Sleep((int)ts.TotalMilliseconds);
		}
		
		private void ThreadProc(object state)
		{
			if (parameterizedAction != null)
				parameterizedAction(state, cancelTokenSource.Token);
			else
				action(cancelTokenSource.Token);
		}
		
		private Action action;
		private Action<object, CancellationToken> parameterizedAction;
		private Task t;
		private CancellationTokenSource cancelTokenSource =
		  new CancellationTokenSource();
	}
	
	public delegate void ThreadStart(CancellationToken cancelToken);
	public delegate void ParameterizedThreadStart(object o,
	  CancellationToken cancelToken);
}

This handles the basics: starting a thread with or without parameters, waiting on a thread (Join), and pausing the sleeping the current thread.  There are just a couple of differences.

Abort

In the traditional .NET framework, Thread.Abort throws a ThreadAbortException in the thread procedure, non-gracefully terminating the thread.  Tasks introduce a cooperative cancellation mechanism that allows the thread to terminate gracefully when it is at a convenient stopping place.  Cooperative means that the thread procedure must have a means of periodically checking whether it should terminate.  This is done with a CancellationToken.  Thus, we must provide this token to the thread procedure.  I’ve redefined the ThreadStart and ParameterizedThreadStart to add the token as an extra parameter.  This means a minor change in your thread procedure declaration.  If you don’t need support for Thread.Abort in your code migration, you can just redefine these as:

public delegate void ThreadStart();
public delegate void ParameterizedThreadStart(object o);

The above definitions match the original .NET delegate types, so your original Thread-based code can compile with no changes.

If you do require Abort, use the earlier delegate definitions with the CancellationToken parameter.  In your thread procedure, implement the abort by checking token.IsCancellationRequested.  If true, simply return from the thread procedure to end the thread.  For example:

Thread t = new Thread(MyThreadProc);
t.Start();

private void MyThreadProc(CancellationToken cancelToken)
{
    while(true)
    {
        if (cancelToken.IsCancellationRequested)
            return;
	
        // do some useful work here
    }
}

And that’s all there is to it!


No Replies to "Windows Store Apps: Threads to Tasks"


    Got something to say?

    Some html is OK