multithreading - C#: Method Invoke never returns -
i've got threaded invoke call never returns.
the thread runs fine right until call line ways, "owner.invoke(methinvoker);
"
when debugging, can step, step, step, once hit owner.invoke
... it's over!
control owner; public event reportceprogressdelegate progresschanged; public void reportprogress(int step, object data) { if ((owner != null) && (progresschanged != null)) { if (!cancellationpending) { threadeventarg e = new threadeventarg(step, data); if (owner.invokerequired) { methodinvoker methinvoker = delegate { progresschanged(this, e); }; owner.invoke(methinvoker); } else { progresschanged(this, e); } } else { mrereporter.set(); mrereporter.close(); } } }
fyi: custom class mimics backgroundworker
class, not available on controls not have forms.
thinking invoke might not required, manually stepped cursor in debugger on part of code , tried calling progresschanged
directly, vs2010's debugger threw cross thread exception.
edit:
due first 3 comments have received, wanted update progresschanged
method:
worker.progresschanged += delegate(object sender, threadeventarg e) { if (progressbar1.style != progressbarstyle.continuous) { progressbar1.value = 0; object data = e.data; if (data != null) { progressbar1.maximum = 100; } progressbar1.style = progressbarstyle.continuous; } progressbar1.value = e.progresspercentage; };
there breakpoint on first line of anonymous method, never gets hit either.
edit 2
here more complete listing of call thread:
list<tabledata> tlist = collecttablesfromform(); if (0 < tlist.count) { using (sqlcereporter worker = new sqlcereporter(this)) { (int = 0; < tlist.count; i++) { manualresetevent mre = new manualresetevent(false); worker.startthread += sqlceclass.savesqlcedatatable; worker.progresschanged += delegate(object sender, threadeventarg e) { if (progressbar1.style != progressbarstyle.continuous) { progressbar1.value = 0; object data = e.data; if (data != null) { progressbar1.maximum = 100; } progressbar1.style = progressbarstyle.continuous; } progressbar1.value = e.progresspercentage; }; worker.threadcompleted += delegate(object sender, threadresultarg e) { cursor = cursors.default; progressbar1.visible = false; progressbar1.style = progressbarstyle.blocks; if (e.error == null) { if (e.cancelled) { messagebox.show(this, "save action cancelled.", "save table " + tlist[i].tablename); } } else { messagebox.show(this, e.error.message, "error saving table " + tlist[i].tablename, messageboxbuttons.ok, messageboxicon.error); } mre.set(); }; worker.runworkerasync(tlist[i]); progressbar1.value = 0; progressbar1.style = progressbarstyle.marquee; progressbar1.visible = true; cursor = cursors.waitcursor; mre.waitone(); } } }
i hope isn't overkill! hate presenting information, because people critiquing style. :)
worker.runworkerasync(tlist[i]); //... mre.waitone();
that's guaranteed deadlock. delegate pass control.begin/invoke() can run when ui thread idle, having re-entered message loop. ui thread isn't idle, blocked on waitone() call. call can't complete until worker thread completes. worker thread can't complete until invoke() call completed. call can't complete until ui thread goes idle. deadlock city.
blocking ui thread fundamentally wrong thing do. not because of .net plumbing, com requires never block. that's why bgw has runworkercompleted event.
Comments
Post a Comment