c# - SynchronizationContext flows on Task.Run but not on await -


after reading stephen toub's article on synchronizationcontext i'm left question output of piece of .net 4.5 code:

private void btndosomething_click() {     logsynccontext("btndosomething_click");     doitasync().wait(); } private async task doitasync() {     logsynccontext("doitasync");     await performservicecall().configureawait(false); //to avoid deadlocking } private async task performservicecall() {     logsynccontext("performservicecall 1");     httpresponsemessage message = await new httpclient     {         baseaddress = new uri("http://my-service")     }     .getasync("/").configureawait(false); //to avoid deadlocking     logsynccontext("performservicecall 2");     await processmessage(message);     logsynccontext("performservicecall 3"); }  private async task processmessage(httpresponsemessage message) {     logsynccontext("processmessage");     string data = await message.content.readasstringasync();     //do data }  private static void logsynccontext(string statementid) {     trace.writeline(string.format("{0} {1}", statementid, synchronizationcontext.current != null ? synchronizationcontext.current.gettype().name : taskscheduler.current.gettype().name)); } 

the output is:

btndosomething_click windowsformssynchronizationcontext

doitasync windowsformssynchronizationcontext

performservicecall 1 windowsformssynchronizationcontext

performservicecall 2 threadpooltaskscheduler

processmessage threadpooltaskscheduler

performservicecall 3 threadpooltaskscheduler

but expect performservicecall 1 not on windowsformssynchronizationcontext since article states "synchronizationcontext.current not “flow” across await points"...

the context not passed when calling performservicecall task.run , async lambda, this:

await task.run(async () => {     await performservicecall(); }).configureawait(false); 

can clarify or point documentation on this?

stephen's article explains synchronizationcontext doesn't "flow" executioncontext (although synchronizationcontext part of executioncontext).

executioncontext flowed. when use task.run if synchronizationcontext flow task.run execute on ui thread , task.run pointless. synchronizationcontext doesn't flow, rather gets captured when asynchronous point (i.e. await) reached , continuation after posted (unless explicitly stated otherwise).

the difference explained in quote:

now, have important observation make: flowing executioncontext semantically different capturing , posting synchronizationcontext.

when flow executioncontext, you’re capturing state 1 thread , restoring state such it’s ambient during supplied delegate’s execution. that’s not happens when capture , use synchronizationcontext. capturing part same, in you’re grabbing data current thread, use state differently. rather making state current during invocation of delegate, synchronizationcontext.post you’re using captured state invoke delegate. , when , how delegate runs implementation of post method.

that means in case when output performservicecall 1 current synchronizationcontext indeed windowsformssynchronizationcontext because haven't yet reached asynchronous point , still in ui thread (keep in mind part before first await in async method executed synchronously on calling thread logsynccontext("performservicecall 1"); happens before configureawait(false) happens on task returned performservicecall).

you "get off" ui's synchronizationcontext when use configureawait(false) (which disregards captured synchronizationcontext). first time happens on httpclient.getasync , again on performservicecall.


Comments

Popular posts from this blog

javascript - AngularJS custom datepicker directive -

javascript - jQuery date picker - Disable dates after the selection from the first date picker -