Wednesday, 26 October 2011

.net 4 Tasks Not Starting

This is another post about a problem that I could have solved much quicker if I’d found the right blog posts. It’s common enough that .net 4.5 will include a new Task.Run method that saves you from this mistake.

The symptom was that a task that was supposed to run in the background while the UI thread did some other work wasn’t starting – it was scheduled but didn’t run.

The reason was that the supposed background task was started from some code that was (further back in the call stack) inside a task that had been scheduled on the UI thread, using a common pattern of specifying the scheduler.

If you’re already inside a task, creating or starting a new task without specifying a scheduler picks up the scheduler of the parent task, not the default scheduler.

        public void ButtonClicked()

        {

            var onUiThread = TaskScheduler.FromCurrentSynchronizationContext();

            var task = new Task(() => DoSomethingInTheBackground());

            task.ContinueWith(t => DoSomethingUIRelated(), onUiThread);

            task.Start();

        }

 

        public void DoSomethingUIRelated()

        {

            var offUiTask = Task.Factory.StartNew(() => SomethingElseForTheBackground());

            ///

            /// Do some UI-thread stuff

            ///

            offUiTask.Wait();

        }

 

 

So, on the UI thread, a task is created which calls DoSomethingInBackground. When that is finished, DoSomethingUIRelated is called – on the UI thread by specifying the scheduler onUiThread.

But when the task to call SomethingElseForTheBackground is created, it inherits the UI thread scheduler, and because the UI thread starts a Wait for it, it never gets a chance to run.

The solution is to specify TaskScheduler.Default for offUiTask, or to use the new Task.Run method when .net 4.5 comes along.