Here is some easy piece of code to show the unexpected behavior:
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
_UI = TaskScheduler.FromCurrentSynchronizationContext();
Loaded += new RoutedEventHandler(MainWindow_Loaded);
}
TaskScheduler _UI;
void MainWindow_Loaded(object sender, RoutedEventArgs e)
{
Task.Factory.StartNew(() =>
{
//Expected: Worker thread
//Found: Worker thread
DoSomething();
})
.ContinueWith(t =>
{
//Expected: Main thread
//Found: Main thread
DoSomething();
Task.Factory.StartNew(() =>
{
//Expected: Worker thread
//Found: Main thread!!!
DoSomething();
});
}, _UI);
}
void DoSomething()
{
Debug.WriteLine(Thread.CurrentThread.ManagedThreadId.ToString());
}
}
Why is the inner task executed in the main thread?
How can i prevent this behavior?
Unfortunately, the Current task scheduler, when you’re running your continuation, becomes the
SynchronizationContextTaskSchedulersetup by yourTaskScheduler.FromCurrentSynchronizationContext.This is discussed in this Connect Bug – and was written this way by design in .NET 4. However, I agree that the behavior leaves a bit to be desired here.
You can work around this by grabbing a “background” scheduler in your constructor, and using it:
Once you have that, you can easily schedule your “background” task appropriately:
Also, in this case, since your operation is at the end, you could just put it in its own continuation and get the behavior you want. This, however, is not a “general purpose” solution, but works in this case: