FAQ :: StartNew() with TaskScheduler.FromCurrentSynchronizationContext() doesn’t work?

FAQ :: StartNew() with TaskScheduler.FromCurrentSynchronizationContext() doesn’t work?

  • Comments 5

We’ve seen a number of folks write the following code to execute on the UI thread and get unexpected behavior.


TaskScheduler uiScheduler = TaskScheduler.FromCurrentSynchronizationContext();

Task uiTask = Task.Factory.StartNew(delegate
    // … Update UI component; BUG!
}, uiScheduler);

The issue is that the StartNew call will bind to the following overload…


public Task StartNew(Action<Object> action, Object state);

…because the following overload does not exist!


public Task StartNew(Action action, TaskScheduler scheduler);

 As a result, uiScheduler just becomes the AsyncState for uiTask instead of being the TaskScheduler on which it executes, so the UI updates will end up running on the ambient scheduler captured during the StartNew call (usually not desired).  Once the issue is identified, it’s easy to pick the right overload:


Task t = Task.Factory.StartNew(delegate
    // … Update UI component
}, CancellationToken.None, TaskCreationOptions.None, uiScheduler);


Note that you won’t run into the same confusion with ContinueWith (the API that’s more commonly used with TaskScheduler.FromCurrentSynchronizationContext), because we do have overloads of ContinueWith that take just TaskScheduler.


So why didn’t we add overloads of StartNew that take just TaskScheduler?  The short answer is that we were trying to reduce the number of overloads and didn’t expect this particular issue to be problematic.  It’s something we’d love to address, but unfortunately, adding the new overloads now could potentially break existing code that actually wanted to pass a TaskScheduler as the AsyncState.

Leave a Comment
  • Please add 4 and 2 and type the answer here:
  • Post
  • I think the risk of breaking is very low because most people will use tasks with closures and without the state parameter (that is surely there for performance reasons).

  • and maybe consider adding named parameters with appropriate defaults so we can avoid nasty little things like this.

  • Thanks for the comments!  Agreed that the risk of breakage is low, but the mentality with breaking changes in .NET is "if it can happen, it will."  Regarding optional/default parameters, I can see the value, but it would be specific to C#.

  • FAQ :: StartNew() with TaskScheduler.FromCurrentSynchronizationContext() doesn’t work?

  • Awesome, this was driving me nuts

Page 1 of 1 (5 items)