1

please take a look at the following code:

So, I grab the current context (WinForms thread), start a new task with that context, and attach a synchonous continuation with the Default task scheduler. As far as I understand, a continuation should start on a threadpool thread. UI thread doesn't belong to threadpool. But instead, all code including a continuation, is running synchonously on the same thread. That's quite unexpected for me.

Btw, if I set the continuation options as TaskContinuationOptions.None, it's run on another thread as it should. Seems like continuation options make preference over task scheduler, despite they are just hints and scheduler is a requirement.

TaskScheduler uiContext = TaskScheduler.FromCurrentSynchronizationContext();
Console.WriteLine("start thread {0}", Thread.CurrentThread.ManagedThreadId);

Task.Factory.StartNew(() =>
{
    Console.WriteLine("ui thread {0}", Thread.CurrentThread.ManagedThreadId);
}, CancellationToken.None, TaskCreationOptions.None, uiContext).ContinueWith(t =>
{
    Console.WriteLine("continuation thread {0}", Thread.CurrentThread.ManagedThreadId);
}, CancellationToken.None, TaskContinuationOptions.ExecuteSynchronously, TaskScheduler.Default);

Is it a bug or expected behaviour?

What can I do to guaranteed run of the continuation code outside of UI thread independently of the parent task context and continuation options? Some custom task scheduler?

A note: I know this is a legacy code now, and async/await is the way to go.

Manoj Choudhari
  • 5,277
  • 2
  • 26
  • 37
lilo0
  • 895
  • 9
  • 12
  • 2
    See [here](https://devblogs.microsoft.com/pfxteam/when-executesynchronously-doesnt-execute-synchronously/): The default TaskScheduler permits the Task to run synchronously. – canton7 Feb 05 '20 at 09:30
  • Thx for the link! It's actually close to 3rd case in that article. IMO, `Default` task scheduler should deny a synchonous continuation in that case, isn't it? – lilo0 Feb 05 '20 at 09:38
  • This post is a little disjointed, I mean it seems to be doing exactly what you are telling it to do, how about, we start with what you want to achieve? – TheGeneral Feb 05 '20 at 09:42
  • So, I want to attatch a continuation to a task, which Must run on a threadpool thread(not UI thread). Sample code shows that default task scheduler is not enouth for all cases. – lilo0 Feb 05 '20 at 09:48
  • Can't you just remove the `TaskContinuationOptions.ExecuteSynchronously` option? – Theodor Zoulias Feb 05 '20 at 09:53
  • I think I can, but would that be enouth? Would it _always_ run asynchonously then? In reality, I just would like to know why it works what way. – lilo0 Feb 05 '20 at 10:00
  • Doesn't the article I linked explain that? `ExecuteSynchronously` is a request to the `TaskScheduler` to run it synchronously. The `TaskScheduler` can deny that request if it wants, or it might be denied for other reasons. – canton7 Feb 05 '20 at 10:10
  • No, it doesn't explain that. I can't understand why the task scheduler wants at all to run the task synchonously in that case. – lilo0 Feb 05 '20 at 10:19
  • I don't follow. You can't understand why the TaskScheduler might allow a Task to run synchronously, even though the user asked it to run the Task synchronously? – canton7 Feb 05 '20 at 10:20
  • Yes. Imagine a more common scenario: you have a threadpool task, and attatch a continuation to it with the task scheduler, related to the UI. In that case, no matter that continuation options are, the task scheduler would run that continuation async over UI thread. The article explains exactly that. Task scheduler can't run it synchonously in that case. What I don't understand is how the sample case is different. Shouldn't it for the same reasons deny synchronous continuation? – lilo0 Feb 05 '20 at 10:28
  • 2
    In your question, you're using the default TaskScheduler. That doesn't care whether the Task is run on the thread pool or somewhere else. If **you** said "please run this synchronously", the default TaskScheduler has no reason to deny your request. However a TaskScheduler which is specifically written to **only** run stuff on an STA thread would have a good reason to deny a request to run a continuation synchronously on another thread. – canton7 Feb 05 '20 at 10:29
  • That leads me to the conclusion, that the statement `default task scheduler uses only thread pool threads` is incorrect. Isn't that a general opinion? Is it possible to make a custom task scheduler, which would run the tasks, optionally synchonously, but only over threadpool threads? – lilo0 Feb 05 '20 at 10:39
  • That is indeed what [the docs say](https://learn.microsoft.com/en-us/dotnet/api/system.threading.tasks.taskscheduler?view=netframework-4.8#remarks). Uses the ThreadPool, but tasks may be inlined – canton7 Feb 05 '20 at 10:42

0 Answers0