0

So let's say I have a method

async Task<int> GetStackOverflowAsync()
{
    Task<int> longRunningCpuBoundTask = Task<int>.Run(() => 
       {
            // some long-running CPU-bound task that returns an int
       })
       .ConfigureAwait(continueOnCapturedContext: true);
    return await longRunningCpuBoundTask;
}

and let's say the captured context is a UI thread that needs the int. So I understand that Task.Run offloads the long-running CPU-bound task to another thread, but I'm wondering which thread checks for the completion of that task.

I imagine what happens is like

UI Thread |- do UI stuff -||- check longRunningCpuBoundTask -||- do more UI stuff -||- check longRunningCpuBoundTask |- Start from we left off at the await -| longRunningCpuBoundTask Thread |------------------------------------------------------------ done! ---------------------------------------|

Can someone correct my understanding?

user7127000
  • 3,143
  • 6
  • 24
  • 41
  • There isn't a part of the system that polls the task to see if it's completed. Rather, once the task is complete, the compiler-generated code calls the captured SynchronizationContext to schedule some more work. – yaakov Jan 06 '17 at 06:19

1 Answers1

2

There is no polling for task completion. When task is completed infrastructure code calls SynchronizationContext.Post to finish the operation on whatever thread/other context the SynchronizationContext considers necessary. It is up to SynchronizationContext to decide how it will schedule operation on the thread.

In case of WinForms (UI context) it will eventually post regular Windows message to a control and when the message is handled (similar to any other messages like "mouse click") code after await will be executed.

So flow is approximately following.

  UI thread                     |  Other thread    
  start click event
    start new task (if await'ed |
     save rest of the method    |
     as continuation delegate)  |
  return from click event       |    - thread created or obtained from pool
  handle mouse event            |    do work
  handle key event              |    do work
  handle mouse event            |    done - call Post on context
  ...                           |    post "special" message to event loop for the app
  handle mouse event            |    - thread closed or returned to pool
  handle "special" event - run  |    -
  continuation delegate)        |

Note that there is no checking of the state of the thread. Also you can see how wait causes deadlock if event handler before "handle special event" will stop processing other Windows events due to Thread.Sleep or any other busy wait.

You can read through code of WindowsFormsSynchronizationContext.Post to see exactly what is happening (BeginInvoke which in turn causes message to be posted to regular event loop). Also there are many questions on this topic like What does SynchronizationContext do?.

Community
  • 1
  • 1
Alexei Levenkov
  • 98,904
  • 14
  • 127
  • 179