c# - WinForms message loop not responsive -
i'm deliberately abusing message loop in windows forms application, "just fun" project progressed beyond level of understanding. while task running form unresponsive. yes, there lots of other questions this, in case deliberately avoiding work on thread (to win bet against myself?)
i have function runs (many) short slices of time on ui thread: get_iscomplete()
checks if task complete; dowork()
loops 0 1000 (just keep cpu warm). task started calling control.begininvoke(new action(continuewith), control);
whereupon (tail recursively) calls until completion, running short slice of work on ui thread.
public void continuewith(control control) { if (!iscomplete) { dowork(); onnext(control); control.begininvoke(new action(continuewith), control); } else { oncompleted(control); } }
i expected application process other events (mouse clicks, control repaints, form moves etc.) seems calls getting more priority i'd like.
any suggestions?
the control.begininvoke() call places delegate pass in internal queue , calls postmessage() wake message loop , pay attention. that's gets first begininvoke going. input events (mouse , keyboard) go on message queue, windows puts them there.
the behavior didn't count on in code runs when posted message retrieved. doesn't dequeue one invoke request , executes it, loops until entire invoke queue emptied. way code works, queue never emptied because invoking continuewith() adds invoke request. keeps looping , processing invoke requests , never gets around retrieving more messages message queue. or put way: pumping invoke queue, not message queue.
the input messages stay in message queue until code stops adding more invoke requests , regular message loop pumping resumes, after code stops recursing. ui frozen while takes place because paint events won't delivered either. generated when message queue empty.
it important works way does, postmessage() call isn't guaranteed work. windows doesn't allow more 10,000 message in message queue. control.begininvoke() has no such limit. emptying invoke queue completely, lost postmessage message doesn't cause problem. behavior cause other problems though. classic 1 calling backgroundworker.reportprogress() often. same behavior, ui thread flooded invoke requests , doesn't around normal duties anymore. frown upside down on runs this: "i'm using backgroundworker ui still freezes".
anyhoo, experiment abysmal failure. calling application.doevents() required force message queue emptied. lots of caveats that, check this answer details. upcoming support async keyword provide way this. not sure if treats message priority differently. rather doubt it, control.begininvoke() pretty core. 1 hack around problem using timer short interval. timer messages go on message queue (sort of) have low priority. input events processed first. or low level hack: calling postmessage own message , overriding wndproc detect it. that's getting bit off straight , narrow. application.idle event useful processing after input events retrieved.
Comments
Post a Comment