Posted By: spivonious | Oct 23rd @ 9:29 AM
page 1 of 1
Comments: 24 | Views: 262

I've got a WPF app that does some major multi-threading in its worker classes. My problem is that as soon as all of the worker threads complete, the app shuts down. No errors, no exceptions, just shuts down the app and throws me back into the IDE.

 

After confirming that the threading is indeed working as intended with some debug.print statements, I am at a loss as to why this is happening.

 

Any ideas on further debugging steps?

 

The basic structure is this:

 

interface bound to "runner" object

runner holds collection of "sample" objects and spawns a thread for each sample

each sample holds as collection of "combinations" and spawns a thread for each combination

 

I'm using events to track when threads finish and then when everything is finished, I update the interface. Immediately after this step, the application shuts down.

How exactly are you sending the events from the worker thread to the user interface? In general you cannot call directly into the user interface from another thread than the one that created the user interface. You may need to pass the calls through the WPF Dispatcher.

 

figuerres
figuerres
???

almost sounds like the lackof workers is possibly creating a fault that sends an exit message to the gui thread....

or a fault on no workers is crashing the gui.

figuerres
figuerres
???

what happens if you create runner and the gui but nothing else?

 

does that crash / exit or not?

 

if it does then it's there

if not then one of the other threads is evil.

 

also do you have the .net source debug turned on ?

it might help in seeing where it's dying.

What happens when you run the application in the debugger? No exceptions?

 

 

Check the Output window of the IDE, maybe there's some debugger information in it (after the debugger exits). One cause for a process to exit without a trace is a stack overflow but normally you should see a StackOverflowException in the debugger if that happens. Hmm, maybe it's a stack overflow in an unmanaged thread, not sure how the managed debugger reacts to that...

 

 

Is this using the Thread Pool by any chance?

 

Classic race condition scenario if it is: you call CheckAccess whilst running on a thread and get true, before anything else happens the thread gets suspended, some time later the code starts again only this time on an entirely different thread pool thread (which would have got false from CheckAccess). Boom! Appcrash.

 

Solution: Always, always, use Invoke if you're using a thread pool.

stevo_
stevo_
Human after all

Not specifically related to the errors but spinning up threads 'on demand' for every task you want to run isn't really the best way to handle threading, because you have no context of how many threads you are spinning up for the entire app.

 

You would be much better abstracting your tasks so you can purely say 'here is some more work', and have a pool of workers (or something more advanced like the tpl) manage assigning threads to do work.

stevo_
stevo_
Human after all

Thats not what an abstraction of tasks is (predetermined), its saying.. I don't care who does it, I want it done.

 

The TPL for example by default only spawns a single thread for each processor (so two for a dual core), and it considers them as delegates for a distinct actual processor.. it then enqueues work to them.

 

The idea is that in general purpose threading (ie not super tweaked custom arranged threading), the optimal amount of working threads is equal to the amount of processing units you have.. and similar to how the story of .net programs actually in some cases being faster than native because the compiler has so much more context about what you are trying to do, allowing it to generate better native code.. the task story is the same.. the 'tasks manager' as an entity has a much better context of how to best schedule threads for your entire app.. of course, you can pick to do a lot of work and manually manage threads for absolute performance, but the ROI in most cases is probably slim.

Blue Ink
Blue Ink
C you

I don't know if that's your case, but you will get a System.Reflection.TargetParameterCountException if you call Dispatcher.Invoke passing the wrong number of arguments for the delegate.

Personally, I use lambdas. This way I can get the compiler to check the parameters and intellisense.

exoteric
exoteric
I : Next<I>

The Parallel Extensions for .Net ("Px") is really nice this way, where you decide work resolution and Px decides optimal thread count based on hardware. So you can be quite aggressive on creating many tasks and expect to scale without unnecessary thread overhead - just some extra object creation overhead.

figuerres
figuerres
???

I will guess that at some level both priority and delegate evaluate down to an int value.

seems like it would still complain in .Net but I can see how at the x86 level a number is a number. Smiley

Blue Ink
Blue Ink
C you

Both versions exist (you may have noticed that if you hover on Invoke, you get a tooltip with "+9 overloads").

Yet, Intellisense only show four of them, as the other six have attributes that hide them ([Browsable(false), EditorBrowsable(EditorBrowsableState.Never)]).

It has been like that since .NET 2.0, so there must be some good reason for the hidden overloads, but I fail to see what that might be.

 

 

 

exoteric
exoteric
I : Next<I>

Hi Spinovious, as we're both looking at threading and I was curious about the Thread.IsBackground (to set or not to set), I found this post which (on a quick skim) may be relevant to your exact problem

 

http://msmvps.com/blogs/jonathangreensted/archive/2005/02/16/36077.aspx 

Sven Groot
Sven Groot
My name has 9 letters. Coincidence? I think not...

As a guess, Dispatcher.Invoke uses params, so if you're manually passing in an object[], maybe you've got an errant parameter somewhere that is causing it to interpret the object[] as one of the parameters instead of the entire parameter list. It would be trying to convert it to a string if one of the parameters is a string.

 

Also, can't you break on the exception and check the call stack, would save a lot of guesswork.

Blue Ink
Blue Ink
C you

Sorry if I'm missing something obvious... but why don't you use lambdas instead of passing arguments to Invoke?

 

Dispatcher.Invoke((Action) (() => MyMethod(argument1, argument2, argument3)), DispatcherPriority.Whatever);

 

Never checked how it fares in terms of performance, but it feels much easier to me.

page 1 of 1
Comments: 24 | Views: 262
Microsoft Communities