Threading problem

  • Thread starter Thread starter Davor Dundovic
  • Start date Start date
D

Davor Dundovic

I'm developing one small "windows application" in C# (Visual Studio
2005) and I have a couple of questions ...


Startup form creates an instance of one of my classes. That instance
creates a new thread which has an endless loop.



1.

If I just close the form (mouse click on "X" for instance), process is
left hanging.

Why doesn't it get collected by garbage collector ?


2.

If I execute Thread.Abort() and then close the form - same thing
happens.

Why doesn't it get collected by garbage collector ?


3.

If I execute Thread.Abort() and Thread.Join() and then close the form
- everything is OK. No orphan processes are left hanging.

So I made destructor in my class that does exactly this.

If I just close the form, the destructor in my class doesn't get
called.

Why ?


4.

If I execute Thread.Abort() and Thread.Join() and then attempt to
close the form, destructor gets called ?!?

Why didn't it got called in section 3. ?




I hope someone will have good will and knowledge to answer my
questions. ;-)




Regards, Dundo.
 
OK - there isn't really enough information there to give a complete
answer, but some thoughts:

* the second thread: did you set IsBackground = true?
* it is bad practice to call Thread.Abort(); it would be preferable to
toggle a flag somewhere (even a volatile bool would do) that the other
thread checks periodically, and gracefully exits
* how are you showing your main form? form.Show(), form.ShowDialog(),
or Application.Run(form)? The reason I ask is that a form that is
shown modally (ShowDialog) doesn't get Dispose()d automatically
* can't really comment on the abort/join oddities without something
demonstrable...

Marc
 
I'm developing one small "windows application" in C# (Visual Studio
2005) and I have a couple of questions ...

Startup form creates an instance of one of my classes. That instance
creates a new thread which has an endless loop.

1.

If I just close the form (mouse click on "X" for instance), process is
left hanging.

Why doesn't it get collected by garbage collector ?

The garbage collector deals with objects, not processes. The process
will exit when there are no non-background threads left running. My
guess is that your new thread isn't a background thread.
2.

If I execute Thread.Abort() and then close the form - same thing
happens.

In that case it sounds like another thread may be involved somewhere.
Break into your code in the debugger and see which threads are still
running.
Why doesn't it get collected by garbage collector ?

Again, the garbage collector really isn't involved here.
3.

If I execute Thread.Abort() and Thread.Join() and then close the form
- everything is OK. No orphan processes are left hanging.

That sounds pretty odd. As Marc said, Thread.Abort should be avoided
anyway. See
http://pobox.com/~skeet/csharp/threads/shutdown.shtml
So I made destructor in my class that does exactly this.

Using a finalizer is generally a bad idea. They act extremely non-
deterministically. Combining them with threads (which can also be hard
to reason about) sounds like a very, very bad idea.
If I just close the form, the destructor in my class doesn't get
called.

Why ?

Does your other thread have an active reference to the form?
4.

If I execute Thread.Abort() and Thread.Join() and then attempt to
close the form, destructor gets called ?!?

Why didn't it got called in section 3. ?

Presumably my guess was right about the code in the other thread
having a reference to the form.
I hope someone will have good will and knowledge to answer my
questions.  ;-)

A short but complete program demonstrating the problem would really
help.

See http://pobox.com/~skeet/csharp/complete.html

Jon
 
* the second thread: did you set IsBackground = true?


That's it !

That was quick and helpfull answer ! Thnx !

Now I set it to true and it works fine.

* it is bad practice to call Thread.Abort(); it would be preferable to
toggle a flag somewhere (even a volatile bool would do) that the other
thread checks periodically, and gracefully exits


I've read that but I have a blocking call (UdpClient.Receive) in that
thread so I can't check the state of some flag.

Of course, I could do it asynchroniously (BeginReceive/EndReceive) but
I'm bit lazy ...

* how are you showing your main form? form.Show(), form.ShowDialog(),
or Application.Run(form)? The reason I ask is that a form that is
shown modally (ShowDialog) doesn't get Dispose()d automatically


Application.Run(new Form1());

* can't really comment on the abort/join oddities without something
demonstrable...


OK, now it's obvoius that thread was running in foreground and as such
prevented application to terminate.
 
The garbage collector deals with objects, not processes. The process
will exit when there are no non-background threads left running. My
guess is that your new thread isn't a background thread.


I thought since thread is an object it would be collected too.

Anyway, thread was a foreground one. That was the problem.

Now I've set it to be a background and it works fine.

That sounds pretty odd. As Marc said, Thread.Abort should be avoided
anyway. See


How would you break from a thread that is block by a blocked call ?

That is the situation I have.

I could use async calls but didn't want to.

Does your other thread have an active reference to the form?


No it doesn't but it's a part of that class and since it won't
terminate (foreground thread) I suppose GC doesn't try to collect that
class.



Thnx !
 
I thought since thread is an object it would be collected too.

There's an object providing a representation of the thread, but the
thread itself isn't an object. It's like a file - just because a
FileInfo may be garbage collected doesn't mean the file is deleted.
Anyway, thread was a foreground one. That was the problem.

Now I've set it to be a background and it works fine.
Right.



How would you break from a thread that is block by a blocked call ?

If I want to shut down the process, I'd make sure that the thread is a
background thread. Otherwise, I'd either avoid blocking calls, or just
let the thread wait.
That is the situation I have.

I could use async calls but didn't want to.

Making things block gives the penalty of not always being able to shut
things down quickly, basically.
No it doesn't but it's a part of that class and since it won't
terminate (foreground thread) I suppose GC doesn't try to collect that
class.

If it's part of that class then it does have an active reference - the
implicit "this" reference.

Jon
 
Back
Top