.net - How to wait for tasks to finish without blocking the UI -
this first question in forum , since i'm not native english speaker hope you'll go easy on me, in case i'm doing or saying wrong.
so, here question:
i solve simple problem (so seems), i'm researching on week , tried different things none of worked far, stumbled on same problem.
what opening progress form, starting 2 long running tasks (for instance getting data 2 databases). these long running tasks report progress progress form, after they're finished progress form closes , form opens show results of 2 long running tasks. both tasks have complete (or cancel/fail) before progress form closes , program goes on (or closes).
so, progress form (form1) contains 2 listboxes (listbox1 , listbox2) , following code:
public delegate sub showprogressdelegate(byval message string) public class form1 public sub addmessage1(byval message string) if string.isnullorempty(message) exit sub end if if me.invokerequired me.invoke(new showprogressdelegate(addressof me.addmessage1), new object() {message}) else me.listbox1.items.add(message) me.listbox1.selectedindex = me.listbox1.items.count - 1 application.doevents() end if end sub public sub addmessage2(byval message string) if string.isnullorempty(message) exit sub end if if me.invokerequired me.invoke(new showprogressdelegate(addressof me.addmessage2), new object() {message}) else me.listbox2.items.add(message) me.listbox2.selectedindex = me.listbox2.items.count - 1 application.doevents() end if end sub end class
then have testclass simulates long running tasks , raises progress events:
imports system.threading public class testclass public event showprogress(byval message string) private _milliseconds ushort public sub new(milliseconds ushort) _milliseconds = milliseconds end sub public function run() ushort integer = 1 20 raiseevent showprogress("run " & i) thread.sleep(_milliseconds) next return _milliseconds end function end class
and have main procedure tries put these 2 together:
imports system.threading.tasks imports system.componentmodel public class start private const multi_thread boolean = true public shared sub main() dim testclass(1) testclass dim testtask(1) task(of ushort) dim result(1) ushort testclass(0) = new testclass(50) testclass(1) = new testclass(100) using frm form1 = new form1 frm.show() addhandler testclass(0).showprogress, addressof frm.addmessage1 addhandler testclass(1).showprogress, addressof frm.addmessage2 if multi_thread testtask(0) = task(of ushort).factory.startnew(function() testclass(0).run) testtask(1) = task(of ushort).factory.startnew(function() testclass(1).run) task.waitall(testtask(0), testtask(1)) result(0) = testtask(0).result result(1) = testtask(1).result else result(0) = testclass(0).run result(1) = testclass(1).run end if removehandler testclass(0).showprogress, addressof frm.addmessage1 removehandler testclass(1).showprogress, addressof frm.addmessage2 frm.close() end using messagebox.show("result 1: " & result(0) & "; result 2: " & result(1)) end sub end class
if set constant multi_thread false, works fine (but sequentially). if set if true, shows form, no progress , never shows resulting message box either. if debug never reaches line after task.waitall(...).
i tried other approaches multi threading working plain threads (no return values), backgroundworkers (only percentage progress, no text messages), begininvoke/endinvoke on delegates, nothing worked or showed same behaviour described above.
i told in forum, task.waitall blocks ui-thread since called on ui-thread, can't believe since msdn states task.waitall waits handed-over tasks finish or fail , didn't hand on ui thread.
so, don't know else try, hope can point out mistake me or show me way try solve little problem.
thank in advance.
update:
did little bit more testing , debugging. if change 2 "me.invoke(...)" in code of form "me.begininvoke(...)" still no progress messages shown in form, @ least tasks work , closing message box. actual delivering or showing of progress messages seems cause problem.
maybe triggers in minds?
thank again.
update ii:
after lot of trial , error seems work, @ least little bit. instead of "me.invokerequired" parts in code of form handed on "taskscheduler.fromcurrentsynchronizationcontext" when creating tasks. @ least got progress messages shown, tasks still don't run parallel. that's topic next question here.
you process might taking of resources available @ system side. starting new task, try starting complete new thread heavy processes
you can start progress ui in separate thread wont stop responding
thread nthread; private void button1_click(system.object sender, system.eventargs e) { nthread = new thread(showdlg); nthread.start(); } private void showdlg() { form1 nwin = new form1(); nwin.showdialog(); }
Comments
Post a Comment