Multiple Threads Within the IDE

D

Doug Thews

I was noticing that when I run a multi-threaded app from within the IDE and
then I close the main form (which spun off all of the threads), that the
Stop/Pause VCR buttons in the debugger are still available & working. It's
like closing the form did not actually cancel the threads.

From my earlier discussions on the newsgroup, I know how people already feel
about Thread.Abort(), so I was wondering what I need to do to "clean up"
when closing a main form that has spun off worker threads (I was under the
impression that this cleanup would automatically happen, but seeing the
Stop/Pause VCR buttons on the debugger being active & working tell me
otherwise).

Any thoughts would be appreciated.
 
J

Jon Skeet [C# MVP]

Doug Thews said:
I was noticing that when I run a multi-threaded app from within the IDE and
then I close the main form (which spun off all of the threads), that the
Stop/Pause VCR buttons in the debugger are still available & working. It's
like closing the form did not actually cancel the threads.
Indeed.

From my earlier discussions on the newsgroup, I know how people already feel
about Thread.Abort(), so I was wondering what I need to do to "clean up"
when closing a main form that has spun off worker threads (I was under the
impression that this cleanup would automatically happen, but seeing the
Stop/Pause VCR buttons on the debugger being active & working tell me
otherwise).

When you spin off the worker threads, make them background instead of
foreground threads. The CLR will shut down when all foreground threads
(eg your UI thread) have finished.
 
R

Richard Blewett [DevelopMentor]

well if you just want the trheads to terminate when teh main thread does set their IsBackground property to true. If you want the threads to come down in a controlled fashion, signal them (by an event, flag or Interrupt) and issue a Join on them before the form closes.

The main issue is that threads created uwing the Thread class will, by default, keep your process running.

Regards

Richard Blewett - DevelopMentor
http://staff.develop.com/richardb/weblog

nntp://news.microsoft.com/microsoft.public.dotnet.languages.csharp/<[email protected]>

I was noticing that when I run a multi-threaded app from within the IDE and
then I close the main form (which spun off all of the threads), that the
Stop/Pause VCR buttons in the debugger are still available & working. It's
like closing the form did not actually cancel the threads.

From my earlier discussions on the newsgroup, I know how people already feel
about Thread.Abort(), so I was wondering what I need to do to "clean up"
when closing a main form that has spun off worker threads (I was under the
impression that this cleanup would automatically happen, but seeing the
Stop/Pause VCR buttons on the debugger being active & working tell me
otherwise).

Any thoughts would be appreciated.

--
Doug Thews
Director, Customer Solutions
D&D Consulting Services
----------------
Visit my Tech Blog at:
http://www.ddconsult.com/blogs/illuminati/





---
Incoming mail is certified Virus Free.
Checked by AVG anti-virus system (http://www.grisoft.com).
Version: 6.0.771 / Virus Database: 518 - Release Date: 28/09/2004



[microsoft.public.dotnet.languages.csharp]
 
D

Doug Thews

So, what is the recommended method for shutting down threads spun off my a
main form in a WinFOrms app?

1. Create all worker threads by setting the IsBackground property to true?
2. Call Thread.Interrupt() followed by Thread.Join() within the Form's
Close event for all worker threads?
 
R

Richard Blewett [DevelopMentor]

As with all important questions ... it depends. If the threads need to come down in a controlled fashion then the UI thread, once it exits from Application.Run can Join on the threads. If they don't need to come down in a controlled fashion but just need to terminate, make them background.

Regards

Richard Blewett - DevelopMentor
http://staff.develop.com/richardb/weblog

nntp://news.microsoft.com/microsoft.public.dotnet.languages.csharp/<[email protected]>

So, what is the recommended method for shutting down threads spun off my a
main form in a WinFOrms app?

1. Create all worker threads by setting the IsBackground property to true?
2. Call Thread.Interrupt() followed by Thread.Join() within the Form's
Close event for all worker threads?
 
D

Doug Thews

Any reason not to put the Interrupt() and Join() calls in the Form's Close
event handler?

BTW ... You guys have provided a lot of good information here - a lot more
than is show in the various threading articles and books (a lot of this IS
NEVER MENTIONED). Makes me think that an article written from the
beginner's perspective, but with THIS information, would be quite helpful.
 
J

Jon Skeet [C# MVP]

Doug Thews said:
Any reason not to put the Interrupt() and Join() calls in the Form's Close
event handler?

I would suggest not using Interrupt, myself - it's not a terribly
nicely controlled way of doing things. I would have a property which is
polled regularly by each worker thread. The only downside of that is
that if a thread gets "stuck" it could hold the app up. To stop that
from being a problem, you could have an extra background thread which
*does* call Thread.Interrupt, or Thread.Abort, or even Environment.Exit
if it's still running say 5 seconds after the UI has shut down.

For code demonstrating what I mean about the polling, see
http://www.yoda.arachsys.com/csharp/threads/shutdown.shtml

As for calling Join() - why bother? What would you want to do after
you'd waited for them? If you're just going to return, then let the
main thread just die and the other threads can die in their own time.
BTW ... You guys have provided a lot of good information here - a lot more
than is show in the various threading articles and books (a lot of this IS
NEVER MENTIONED). Makes me think that an article written from the
beginner's perspective, but with THIS information, would be quite helpful.

If you have any suggestions for how I can improve my article at
http://www.pobox.com/~skeet/csharp/threads I'd be keen to improve it.
 
D

Doug Thews

My only tips would be to not rely on console apps (not much of a real-world
scenario) and move your thread code out from within the Form's class code
and into its own class (as you'd probably see in the real world). I found
out a bunch of scope stuff that changes once you try and do delegates off of
methods within classes, rather than just a method within the Form class.

I'd also recommend somehow that you get the word out about your article. It
doesn't hit very high in Google, and the one's that do are the articles I'm
complaining about right now - the ones that just show console apps with no
meat, no talk about how to safely update the UI from a worker thread, and
how to safely bring down worker threads.

Thanks for asking my opinion.

--
Doug Thews
Director, Customer Solutions
D&D Consulting Services
----------------
Visit my Tech Blog at:
http://www.ddconsult.com/blogs/illuminati/
 
D

Doug Thews

Maybe I missed this in your article (but I don't think so), but ... Is there
a reason that a ThreadInterruptedException does not get raised in a worker
thread if that worker thread just loops without having a Thread.Sleep
command somewhere in the worker thread's loop (even if the Thread is marked
for background before it's started)?

I would've thought that a Sleep wasn't necessary when marking it as
IsBackground before starting it, but until I put at least a Thread.Sleep(0)
(thus giving up at least that timeslice within the loop), my
Thread.Interrupt() from the main thread never generates an exception within
the try...catch clause of my worker thread that surrounds the loop.

--
Doug Thews
Director, Customer Solutions
D&D Consulting Services
----------------
Visit my Tech Blog at:
http://www.ddconsult.com/blogs/illuminati/
 
S

Scott Allen

Hi Doug:

The thread cannot be interrupted until it blocks (ThreadState =
WaitSleepJoin).
 
J

Jon Skeet [C# MVP]

Doug Thews said:
My only tips would be to not rely on console apps (not much of a real-world
scenario) and move your thread code out from within the Form's class code
and into its own class (as you'd probably see in the real world). I found
out a bunch of scope stuff that changes once you try and do delegates off of
methods within classes, rather than just a method within the Form class.

I'll certainly do the latter - that's a good point. I prefer console
apps for demonstration purposes because they don't involve a load of
extra "cruft" - virtually all the code you see is relevant to the point
I'm trying to demonstrate. (Almost all the samples are doing non-real-
world things, but to give building blocks which will help in the real
world. In my experience, sample code which tries to be very real-world
oriented ends up being either confusing or useful for anything other
than that oe particular situation.) Maybe an explanatory paragraph
saying that kind of thing would be helpful.
I'd also recommend somehow that you get the word out about your article. It
doesn't hit very high in Google, and the one's that do are the articles I'm
complaining about right now - the ones that just show console apps with no
meat, no talk about how to safely update the UI from a worker thread, and
how to safely bring down worker threads.

Right. Word is gradually spreading about the article, and I'll keep
plugging it when there are questions about it. Not entirely sure where
else to "advertise" it, to be honest - but any ideas are welcome.
 
R

Richard Blewett [DevelopMentor]

Interrupt will only throw the exception when the thread is in an alertable state (Sleeping, waiting on a synchronization primitive or attempting to joion with another thread). This is how it ensures that the exception doesn't do the damage that Abort can do.

Regards

Richard Blewett - DevelopMentor
http://staff.develop.com/richardb/weblog

nntp://news.microsoft.com/microsoft.public.dotnet.languages.csharp/<##[email protected]>

Maybe I missed this in your article (but I don't think so), but ... Is there
a reason that a ThreadInterruptedException does not get raised in a worker
thread if that worker thread just loops without having a Thread.Sleep
command somewhere in the worker thread's loop (even if the Thread is marked
for background before it's started)?

I would've thought that a Sleep wasn't necessary when marking it as
IsBackground before starting it, but until I put at least a Thread.Sleep(0)
(thus giving up at least that timeslice within the loop), my
Thread.Interrupt() from the main thread never generates an exception within
the try...catch clause of my worker thread that surrounds the loop.
 
S

Santi

A thread ends when it exists the function that it is executing. If the
thread performs a continuos loop you usually use a boolean to control the
execution, something like:

bool run;

void Foo()
{
while( run )
{
// perform whatever
}
}

So what I do to stop and end the thread in a clean way is:

run = false;

this makes the executuion flow to exit the function and end the thread.

regards,
Santiago Corredoira.
 
D

Doug Thews

So, when the OS interrupts the thread because it's gone past its timeslice,
it's not in the WaitSleepJoin state? What state would the thread be in when
the OS is the one who pre-empts it to run other stuff?
 
S

Scott Allen

Thread.Interrupt is a 'soft interrupt', probably implemented by
setting a flag the runtime can check at specific times (before a
thread enters a blocked state, for instance). In fact, the name
interrupt might be a poor choice, except for the fact that we are so
far removed from interrupts with a managed runtime underneath.

The OS uses hardware (the clock) to interrupt a running thread and
make scheduling decisions. If the OS selects another thread it can
perform a context switch, which is saving the current thread's state
(program counter, registers, and other goo) onto the thread's kernel
mode stack, and restoring the same information from the second
thread's kernel mode stack. That's the simplest view, of course.
 
R

Richard Blewett [DevelopMentor]

You're looking at this slightly too low level. What the thread schedular is doing is to some degree irrelevant to you unless you want to give up your timeslice, change priorities, etc.

The crucial thing is to think of the situation as having an infinite number of processors available. In other words your thread will appear to other threads in the state it would be if it were being scheduled (in other words thread scheduling has no effect on your thread's state).

If you try to second guess the thread scheduler its a sure fire way of introducing timing related bugs.

Regards

Richard Blewett - DevelopMentor
http://staff.develop.com/richardb/weblog

nntp://news.microsoft.com/microsoft.public.dotnet.languages.csharp/<[email protected]>

So, when the OS interrupts the thread because it's gone past its timeslice,
it's not in the WaitSleepJoin state? What state would the thread be in when
the OS is the one who pre-empts it to run other stuff?
 
D

Doug Thews

OK, thanks. I wasn't expecting to have to give up my timeslice periodically
just to allow a ThreadInterruptedException to be generated the next time my
thread gets a timeslice, but I understand what you guys are trying to say.
 
J

Jon Skeet [C# MVP]

Santi said:
A thread ends when it exists the function that it is executing. If the
thread performs a continuos loop you usually use a boolean to control the
execution, something like:

bool run;

void Foo()
{
while( run )
{
// perform whatever
}
}

So what I do to stop and end the thread in a clean way is:

run = false;

this makes the executuion flow to exit the function and end the thread.

Note that as written, this isn't thread-safe. Either run should be made
volatile, or you should put a lock round both the reading and writing
of it.

See http://www.pobox.com/~skeet/csharp/threads/volatility.shtml
 
J

Jon Skeet [C# MVP]

Doug Thews said:
How about on your blog, and then try and get references to it on some of the
other major blogs (like Scobleizer, etc).

I don't have a blog - but people probably see more references to the
article in the newsgroups than would read a blog anyway :)

I guess I could see whether any other blogs fancied commenting on it.
I'll have a think - thanks for the suggestion :)
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top