I am still learning the whole Task-concept and TPL. From my current understanding, the SynchronizationContext functions (if present) are used by await
to dispatch the Task "somewhere". On the other hand, the functions in the Task
class do not use the context, right?
So for example Task.Run(...)
will always dispatch the action on an worker thread of the thread pool and ignore the SynchronizationContext.Current
completely. await Foobar()
would use the context to execute the generated task after the await
?
If that is true, my question is: How can I obtain a Task
, that actually runs an action but is dispatched using SynchronizationContext.Current.Send/Post
?
And can anyone recommend a good introduction into SynchronizationContext
, especially when and how they are used by the rest of the framework? The MSDN seems to be very quiet about the class. The top Google hits (here and here) seem to be tailored to Windows Forms dispatching only. Stephen Cleary wrote an article which is nice to learn what contexts already exist and how they work, but I lack understanding of where and when they are actually used.
Use special task scheduler:
Look at the article It's All About the SynchronizationContext by Stephen Cleary.
As you're learning this, it's important to point out that
Task
as used by the TPL is quite different thanTask
as used by async/await, even though they're the same type. For example, TPL commonly uses parent/child tasks, butasync
/await
does not.TPL uses task schedulers to execute its tasks. As Dennis pointed out,
TaskScheduler.FromCurrentSynchronizationContext
will give you a task scheduler that usesPost
on the currentSynchronizationContext
to execute its task.async
/await
usually does not use task schedulers. I have an introductoryasync
/await
post on my blog that includes context information, and I also mention it briefly in my MSDN article (it's easy to overlook, though). Essentially, when anasync
method suspends at anawait
, by default it will capture the currentSynchronizationContext
(unless it isnull
, in which case it will capture the currentTaskScheduler
). When theasync
method resumes, it resumes executing in that context.Dennis pointed out the TPL way of scheduling a task to the current
SynchronizationContext
, but inasync
/await
world, that approach isn't necessary. Rather, you can explicitly schedule tasks to the thread pool viaTask.Run
:I wrote my
SynchronizationContext
article precisely because the MSDN docs were so lacking. I have a little more information on my blog, but all the important bits are in the MSDN article. Many types useAsyncOperation
rather thanSynchronizationContext
directly; the best documentation for this is buried under the EAP docs (section "Threading and Context"). But I should also point out that EAP is effectively obsolete due toasync
/await
, so I wouldn't write code usingAsyncOperation
(orSynchronizationContext
) - unless I was actually writing my ownSynchronizationContext
.