Tuesday 15 June 2010

c# - await not using current SynchronizationContext -



c# - await not using current SynchronizationContext -

i'm getting confusing behavior when using different synchronizationcontext within async function outside.

most of program's code uses custom synchronizationcontext queues sendorpostcallbacks , calls them @ specific known point in main thread. set custom synchronizationcontext @ origin of time , works fine when utilize one.

the problem i'm running have functions want await continuations run in thread pool.

void beginningoftime() { // mycustomcontext queues each endorpostcallback , runs them @ known point in main thread. synchronizationcontext.setsynchronizationcontext( new mycustomcontext() ); // ... later on in code, wait on something, , should go on within // main thread mycustomcontext runs has queued int x = await someotherfunction(); weshouldbeinthemainthreadnow(); // ********* should run in main thread } async int someotherfunction() { // set null synchronizationcontext because function wants continuations // run in thread pool. synchronizationcontext prevcontext = synchronizationcontext.current; synchronizationcontext.setsynchronizationcontext( null ); seek { // want continuation posted thread pool // thread, not mycustomcontext. await blah(); weshouldbeinathreadpoolthread(); // ********* should run in thread pool thread } { // restore previous setsynchronizationcontext. synchronizationcontext.setsynchronizationcontext( prevcontext ); } }

the behavior i'm getting code right after each await executed in seemingly-random thread. sometimes, weshouldbeinthemainthreadnow() running in thread pool thread , main thread. weshouldbeinathreadpoolthread() running

i don't see pattern here, thought whatever synchronizationcontext.current set @ line utilize await 1 define code next await execute. wrong assumption? if so, there compact way i'm trying here?

there mutual misconception await, somehow calling async-implemented function treated specially.

however, await keyword operates on object, not care @ awaitable object comes from.

that is, can rewrite await blah(); var blahtask = blah(); await blahtask;

so happens when rewrite outer await phone call way?

// synchronization context leads main thread; task<int> xtask = someotherfunction(); // synchronization context has been set // null someotherfunction! int x = await xtask;

and then, there other issue: finally inner method executed in continuation, meaning executed on thread pool - not have unset synchronizationcontext, synchronizationcontext (potentially) restored @ time in future, on thread. however, because not understand way synchronizationcontext flowed, quite possible synchronizationcontext not restored @ all, set on thread (remember synchronizationcontext.current thread-local...)

these 2 issues, combined, explain randomness observe. (that is, manipulating quasi-global state multiple threads...)

the root of issue await keyword not allow scheduling of continuation task.

in general, want specify "it not of import code after await on same context code before await", , in case, using configureawait(false) appropriate;

async task someotherfunction() { await blah().configureawait(false); }

however, if absolutely want specify "i want code after await run on thread pool" - that should rare, cannot await, can e.g. continuewith - however, going mix multiple ways of using task objects, , can lead pretty confusing code.

task someotherfunction() { homecoming blah() .continuewith(blahtask => weshouldbeinathreadpoolthread(), taskscheduler.default); }

c# .net synchronizationcontext

No comments:

Post a Comment