Threading problem

Threading problem

am 11.04.2008 16:25:39 von 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.



--
Pozdrav, Dundo.

email: davor dot dundovic at gmail dot com

Re: Threading problem

am 11.04.2008 16:33:40 von Marc Gravell

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

Re: Threading problem

am 11.04.2008 17:03:37 von skeet

On Apr 11, 7:25=A0am, Davor Dundovic wrote:
> 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. =A0;-)

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

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

Jon

Re: Threading problem

am 11.04.2008 17:06:14 von Davor Dundovic

On Fri, 11 Apr 2008 07:33:40 -0700 (PDT), Marc Gravell
wrote:


>* 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.


--
Pozdrav, Dundo.

email: davor dot dundovic at gmail dot com

Re: Threading problem

am 11.04.2008 17:26:48 von Davor Dundovic

On Fri, 11 Apr 2008 08:03:37 -0700 (PDT), "Jon Skeet [C# MVP]"
wrote:


>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.


>> 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


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 !


--
Pozdrav, Dundo.

email: davor dot dundovic at gmail dot com

Re: Threading problem

am 11.04.2008 18:42:12 von skeet

On Apr 11, 8:26 am, Davor Dundovic wrote:
> wrote:
> >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.

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.

> >> 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
>
> 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.

> >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.

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

Jon