.NET 4 Tasks and WPF UI thread

.NET 4 introduced interesting feature – Tasks. In this post I’ll try to cover advanced usage of tasks if applied to WPF/Silverlight development

One common problem for GUI developers is long running operations. Another one is cross-threading synchronization. It seems that Task is real cure for both of them. But this cure should be properly prepared.

Let’s say we have some long running operation that must be performed without blocking main UI thread. Here is how we can call it:

...
// UI operations block
...
Task<bool> saveTagTask = Task.Factory.StartNew<bool>(() =>
            {
                return dataService.SaveOrUpdateDataEntity(dataEntity);
            });
...
// UI operations block
...

As you can see we call SaveOrUpdateDataEntity long running operation using .NET Task. But Task itself doesn’t guarantee that action will be performed inside separate thread.

If applied to our context (WPF GUI application) we must use separate thread to perform background operations. Here is where custom TaskScheduler comes to rescue. Recently Parallel Programming with .NET 4 Samples were introduced. All we need is to reuse StaTaskScheduler which allows to manually specify number of worker threads and guarantees that all tasks will be performed using only those worker threads.

Here are the extension methods:

    public static class ParallelExtensions
    {
        public static Task StartNew(this TaskFactory factory, Action action, TaskScheduler scheduler)
        {
            return factory.StartNew(action, CancellationToken.None, TaskCreationOptions.None, scheduler);
        }

        public static Task<TResult> StartNew<TResult>(this TaskFactory factory, Func<TResult> action, TaskScheduler scheduler)
        {
            return factory.StartNew<TResult>(action, CancellationToken.None, TaskCreationOptions.None, scheduler);
        }

        public static Task<TResult> StartNewSta<TResult>(this TaskFactory factory, Func<TResult> action)
        {
            return factory.StartNew<TResult>(action, sharedScheduler);
        }

        private static TaskScheduler sharedScheduler = new StaTaskScheduler(1);
    }

Third method allows us to use sharedScheduler which internally runs one worker thread:

        static void Main(string[] args)
        {
            Debug.WriteLine(String.Format("Current ThreadID: {0}", Thread.CurrentThread.ManagedThreadId));

            for (int i = 0; i < 10; ++i)
            {

                Task<int> t = Task.Factory.StartNewSta<int>(() =>
                {
                    return Thread.CurrentThread.ManagedThreadId;
                });

                Debug.WriteLine(String.Format("TaskID: {0}, ThreadID: {1}", t.Id, t.Result));
            }
        }

And here is the output:

Current ThreadID: 9
TaskID: 1, ThreadID: 10
TaskID: 2, ThreadID: 10
TaskID: 3, ThreadID: 10
TaskID: 4, ThreadID: 10
TaskID: 5, ThreadID: 10
TaskID: 6, ThreadID: 10
TaskID: 7, ThreadID: 10
TaskID: 8, ThreadID: 10
TaskID: 9, ThreadID: 10
TaskID: 10, ThreadID: 10

EDIT:

Passing TaskScheduler.Default makes the same effect and is preferred way of force separation of Task from GUI thread

2 Responses to “.NET 4 Tasks and WPF UI thread”

  1. Reed Says:

    Tillias,

    The default scheduler when you call Task.Factory.StartNew will always use the ThreadPool (unless the LongRunning hint is on, in which case it uses a dedicated thread). It should never schedule a task to run on the UI thread, since the UI thread should never be setup on a ThreadPool thread. In any case, an STA thread is overkill, as you shouldn’t set the apartment state unless there is a good reason to do so.

    I put a more detailed response to your comment on my blog, for more info.

    -Reed


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

%d bloggers like this: