Home | Contact Us | FAQ | Search & Site Map | Link to Us
Sign In | Join | Other 45 Sites in Network
HomeAnnouncementsFree MagazinesWhite PapersSubmit Content
Discussion GroupsASP.NETWindows FormsLanguages.NET FrameworkVisual Studio.NET
Articles.NET FrameworkASP.NETToolsWindows Forms
.NET DirectoryOpen Source ProjectsUser GroupsWeb Resources
Related Topics
Visual Basic 6SQL ServerMS AccessOther DB ProductsMS Server ProductsMore Topics ...

.NET Forum / .NET Framework / CLR / March 2005

Tip: Looking for answers? Try searching our database.

Foreground threads and garbage collection

Thread view: 
Enable EMail Alerts  Start New Thread
Thread rating: 
Beth Phillips - 28 Mar 2005 20:51 GMT
In the following code, the finalizers for Class1 and Worker are not called
unless I change the thread to a background one or explicitly call
GC.Collect() or . Could someone please explain why?

Thanks

Beth

class MainClass
{
    [STAThread]
    static void Main(string[] args)
   {
       Thread.CurrentThread.Name = "Main thread";
       MainClass.Run();
       Console.WriteLine("Exiting Main method");

       // If the next line is enabled, the Class1 finalizer will be called
       // GC.Collect();
   }

   static void Run()
   {
       ThreadTest t = new ThreadTest();
       t.Init();
       Thread.Sleep( 10000 );
   }
}

public class ThreadTest
{
   public ThreadTest()
   {
   }

   public void Init()
   {
       this.w = new Worker();
       this.w.Start();
   }

   ~ThreadTest()
   {
       this.w.Stop();
   }

   private Worker w;
}

public class Worker
{
   public Worker()
   {
       this.myThread = new Thread( new ThreadStart( this.ThreadProc ) );
       this.myThread.Name = "Counter Thread";
   }

   ~Worker()
   {
       this.Stop();
   }

   void ThreadProc()
   {
       bool stopping = false;
       int i = 0;

       try
       {
           while ( !stopping )
           {
    if ( this.stopEvent.WaitOne( 1000, false ) == false )
       Console.WriteLine( i++ );
    else
       stopping = true;
           }
       }
       catch( Exception e )
       {
           Console.WriteLine( e.Message );
       }
       finally
       {
           Console.WriteLine("Exiting counter thread" );
       }
   }

   public void Start()
   {
       this.myThread.Start();
   }

   public void Stop()
   {
       if ( this.myThread.IsAlive )
       {
           this.stopEvent.Set();
           this.myThread.Join();
       }
   }

   private Thread myThread;
   private AutoResetEvent stopEvent = new AutoResetEvent( false );
}
gyurisc - 28 Mar 2005 20:57 GMT
I think the disposal of an object in .NET is not deterministic. the object
will disposed when the application finished or the Garbage collector decides
that it needs the memory.

Cris

> In the following code, the finalizers for Class1 and Worker are not called
> unless I change the thread to a background one or explicitly call
[quoted text clipped - 100 lines]
>    private AutoResetEvent stopEvent = new AutoResetEvent( false );
> }
Beth Phillips - 29 Mar 2005 10:45 GMT
The problem I have is that the application will not finish unless GC.Collect
is called or the thread is a background one as the counter thread keeps
going.

I don't care when the object which creates the thread gets finalized, but I
do want the thread to stop when the finalization happens. I'm confused as to
why the fact that the thread is a foreground one means created objects are
not garbage collected unless I explicitly tell the CLR to garbage collect.

I could implement IDisposable but I thought this was for times when clean-up
needed to be deterministic or when unmanaged resources were used.

> I think the disposal of an object in .NET is not deterministic. the object
> will disposed when the application finished or the Garbage collector decides
[quoted text clipped - 106 lines]
> >    private AutoResetEvent stopEvent = new AutoResetEvent( false );
> > }
Justin Smith - 28 Mar 2005 20:59 GMT
Finalizers are called on the CLR's timeframe, when forced, or when the
Managed Heap is full.  You cannot rely on the finalizer to be called at a
certain time.  The proper implementation is to add and call a dispose, and
supress the finalize using SupressFinalize.

Justin Smith

> In the following code, the finalizers for Class1 and Worker are not called
> unless I change the thread to a background one or explicitly call
[quoted text clipped - 100 lines]
>     private AutoResetEvent stopEvent = new AutoResetEvent( false );
> }
Justin Smith - 28 Mar 2005 21:11 GMT
One other thing to mention:

Finalization is basically a notification that the object is about to be
collected.  You cannot destroy a single object using a finalization /
destructor.  You can't even count on them being called in a certain order.  
Your finalization  code is actually placed in the finalization queue.  If you
call GC.Collect you are forcing the finalizer to be called since you are
forcing a garbage collection.  Typically you do not want to call GC.Collect
since it is so memory intensive.  You are better off with a dispose method...

> In the following code, the finalizers for Class1 and Worker are not called
> unless I change the thread to a background one or explicitly call
[quoted text clipped - 100 lines]
>     private AutoResetEvent stopEvent = new AutoResetEvent( false );
> }
Beth Phillips - 29 Mar 2005 21:31 GMT
Thanks for the clarification. I was hoping that it was possible to signal for
the thread to stop without the client (MainClass) having to explicitly tell
the implementor (ThreadTest) to do so - i.e. in a similar way to a c++
destructor setting an event which signals to the thread to exit its loop and
clean itself up.

I'm still wondering what it is about the foreground thread that prevents the
finalizers being called though.

> One other thing to mention:
>
[quoted text clipped - 110 lines]
> >     private AutoResetEvent stopEvent = new AutoResetEvent( false );
> > }
Daniel Petersson, Cefalo - 29 Mar 2005 11:17 GMT
Hi,

1. Finalizers are Non-determenistic
2. DON'T block the finalizer thread. (may cause deadlocks or other nasty
stuff)
3. Finalizers are ONLY for unmanaged resources.

How does these items affect your code?
1. Your finalizer can be called by any thread at any time, or not at all.
You will never know, henve non-deterministic. (Finalizer is a ~Foo() in C#,
check msdn)
2. If you block this thread you delay garbage collection and you may even
cause deadlocks. (Or even force CLR to skip GC prior to process exit if you
block it during process termination)
3. You can't touch ANY other managed object. These may already be collected!
Finalizers are for UNMANAGED resources only.

If you need to know when something has completed implement some sort of
callback protcol. I would recomend you to use async delegates instead if you
dont need control of your thread. (Or the ThreadPool)

// Daniel

> In the following code, the finalizers for Class1 and Worker are not called
> unless I change the thread to a background one or explicitly call
[quoted text clipped - 100 lines]
>     private AutoResetEvent stopEvent = new AutoResetEvent( false );
> }
"Chris Lyon [MSFT]" - 29 Mar 2005 18:50 GMT
Hi Daniel

A couple corrections to your points...

| 1. Your finalizer can be called by any thread at any time, or not at all.

Actually, finalizers are only called by the Finalizer thread.  It's a
high-priority thread inside the CLR.  You are correct that it runs
non-deterministically, and under certain circumstances, may not run a
particular finalizer.  It is bad practice to rely on finalizers.

| 2. If you block this thread you delay garbage collection and you may even
| cause deadlocks. (Or even force CLR to skip GC prior to process exit if you
| block it during process termination)

You should not do anything that may block the finalizer thread.  Although
this won't prevent GCs from occuring (this happens on a different thread
which can't be blocked by user code), it may prevent other finalizers from
being run.

| 3. You can't touch ANY other managed object. These may already be collected!
| Finalizers are for UNMANAGED resources only.

This is a common misconception.  If you can touch another managed object,
then it has not been collected.  The problem is, the object may have been
*finalized*, which means it may be in an invalid state.  You should not
touch other managed objects in the same finalization graph (touching a
global or static object is ok).

Finalizers should definitely be used to free unmanaged resources, but you
should follow the Dispose Pattern to minimize the chances of finalizers
being run.

Hope that helps
-Chris

--------------------

| Hi,
|
[quoted text clipped - 123 lines]
| >     private AutoResetEvent stopEvent = new AutoResetEvent( false );
| > }
Daniel Petersson, Cefalo - 31 Mar 2005 06:25 GMT
Hi, Chris

I stand corrected :)

// Daniel

ps I didn't realize that a GC was performed even if i block
the finalizer during process termination. I always assumed
that it was the same thread that ran the finalizers as was
responsible for the collection of memory.

> Hi Daniel
>
[quoted text clipped - 170 lines]
> | >     private AutoResetEvent stopEvent = new AutoResetEvent( false );
> | > }
Beth Phillips - 29 Mar 2005 21:27 GMT
I think asynchronous delegates are what I need. As they use the ThreadPool,
which utilises background threads, is it possible for an executing thread in
the pool to be stopped between BeginInvoke and EndInvoke on the delegate?
Sorry if it is a dumb question, but I'm a complete beginner on managed
threads.

Thanks

> Hi,
>
[quoted text clipped - 123 lines]
> >     private AutoResetEvent stopEvent = new AutoResetEvent( false );
> > }
Daniel Petersson, Cefalo - 31 Mar 2005 06:17 GMT
Hi,

It is not possible to stop any async call in any simple manner
due to the nature of the programming model. Sure you can
save a ref to the thread and then call Thread.Abort on that
reference, however I consider it rather bad programming to
abort threads like this, instead try to find a controlled execution
flow that solves the problem instead.

// Daniel

> I think asynchronous delegates are what I need. As they use the ThreadPool,
> which utilises background threads, is it possible for an executing thread in
[quoted text clipped - 131 lines]
> > >     private AutoResetEvent stopEvent = new AutoResetEvent( false );
> > > }
Beth Phillips - 31 Mar 2005 10:21 GMT
Sorry, I didn't make myself clear. What I meant was when the app shuts down,
any background threads will automatically stop. Does this mean that any
methods that are queued for execution by the thread pool but haven't yet
executed will not be called? I don't want to stop an async call myself, but
want to know what happens if the app shuts down between BeginInvoke and
EndInvoke being called (assuming that scenario is possible).

Thanks for your help

Beth

> Hi,
>
[quoted text clipped - 142 lines]
> > > >     private AutoResetEvent stopEvent = new AutoResetEvent( false );
> > > > }

Rate this thread:







Free Magazines

Get these publications absolutely FREE for up to 12 months. There are no hidden fees and no obligation. Simply choose a title, complete the application form and submit it. Read more ...

Oracle MagazineNetwork ComputingComputer WorldBio-IT WorldeWeekInformation WeekInfosecurity
 
Sign In
Join
My Latest Posts
My Monitored Threads
My Blog
My Photo Gallery
My Profile
My Homepage

Start New Thread
Enable EMail Alerts
Rate this Thread



©2008 Advenet LLC   Privacy Policy - Terms of Use
This website includes both content owned or controlled by Advenet as well as content owned or controlled by third parties.