Solved

Graceful detruction of object containing thread.

Posted on 2011-02-11
6
290 Views
Last Modified: 2012-05-11
I have an arraylist MyList of MyMonitored objects. Within the MyMonitored class is a running thread object.

What is the best practice to remove the MyMonitored instance from MyList? Can I just remove the MyMonitored instance from MyList and let GC handle it, or do need to ensure the thread running within the object has stopped first?  If so, can I just to this within the MyMonitored class's destructor?
0
Comment
Question by:brenlex
6 Comments
 
LVL 9

Expert Comment

by:s_chilkury
ID: 34871359
0
 

Author Comment

by:brenlex
ID: 34871575
Thanks, but not really.  I do not need the thread to invoke any activity outside of its own scope of the instance in which it is run.  I just need to remove the instance of MyMonitored from MyList and be confident that the MyMonitored object destroys itself properly (i.e. the threaded process running within the MyMonitored object has stopped first).

I could expose a public bool var 'HasStopped' within the MyMonitored class and run a while loop before I remove it from MyMonitored list, but I am sure there is a better way...
0
 
LVL 85

Accepted Solution

by:
Mike Tomlinson earned 250 total points
ID: 34872099
If you no longer need the object, or the thread within to run, then you should STOP the thread before removing it.  This way you have more available resources as a whole.  Switching between running threads (while invisible to you) is a burden on the system.

*If you have set the IsBackground() property of the thread to true then it will be killed automatically when the app closes.

Is the nature of the thread such that you can set a flag in the object to cause the thread to exit gracefully?
If not, can you set it up with a ManualResetEvent to break its waitstate and exit?
As a last resort you can call Abort() on the thread to kill it forcefully...
0
What Security Threats Are You Missing?

Enhance your security with threat intelligence from the web. Get trending threat insights on hackers, exploits, and suspicious IP addresses delivered to your inbox with our free Cyber Daily.

 
LVL 33

Assisted Solution

by:Todd Gerbert
Todd Gerbert earned 250 total points
ID: 34872226
As Idle_Mind already pointed out, I wouldn't leave un-needed threads lingering around, waiting for the GC to get to them.  I would implement IDisposable on your MyMonitored object, and have MyMonitored terminate the thread.

As opposed to using a List<MyMonitored> I would create my own collection (inherit from Collection<T>, for example) which itself also implements IDisposable.  This way, you can override the remove method and have it call Dispose() on the MyMonitored object in the collection, in addition to removing it from the list.

MSDN says that a reference to a thread isn't needed, that it'll just keep running through to completion - so I'm not 100% sure whether or not you should clean up the thread when the GC runs the destructor, or just when the Dispose() method is explicitly called (I'm leaning towards the latter).

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Collections.ObjectModel;

class Program
{
	static void Main(string[] args)
	{
		MyList list = new MyList();

		MyMonitoredObject obj = new MyMonitoredObject();
		list.Add(obj);

		list.Remove(obj);
	}
}

public class MyList : Collection<MyMonitoredObject>, IDisposable
{
	private bool disposed = false;

	~MyList()
	{
		Dispose(false);
	}

	public void Dispose()
	{
		Dispose(true);
		GC.SuppressFinalize(this);
	}

	private void Dispose(bool disposing)
	{
		if (!disposed && disposing)
		{
			disposed = true;

			foreach (MyMonitoredObject item in Items)
				item.Dispose();

			Items.Clear();
		}
	}

	protected override void RemoveItem(int index)
	{
		Items[index].Dispose();
		base.RemoveItem(index);
	}
}

public class MyMonitoredObject : IDisposable
{
	private bool disposed = false;
	
	private Thread worker;
	private ManualResetEvent runWorkerFlag;

	public MyMonitoredObject()
	{
		runWorkerFlag = new ManualResetEvent(true);
		worker = new Thread(ThreadProc);
		worker.IsBackground = true;
		worker.Start();
	}

	~MyMonitoredObject()
	{
		// Destructor will be called if GC cleans us up
		Dispose(false);
	}

	public void Dispose()
	{
		// Dispose has been explicitly called
		Dispose(true);
		GC.SuppressFinalize(this); // Tell GC no need to run destructor on this object
	}

	private void Dispose(bool disposing)
	{
		if (!disposed)
		{
			disposed = true;

			// If Dispose has been explicitly called clean up the thread
			// and other managed resources
			if (disposed)
			{
				// Tell thread to exit
				runWorkerFlag.Reset();
			}
			else
			{
				// If Dispose has been called as a result of garbage collection
				// there's a chance the GC might have already cleaned up any 
				// managed objects, including our runWorkerFlag, so the only thing to
				// do here is clean up UN-managed resources - like handles opened
				// with calls to Windows APIs
			}
		}
	}

	private void ThreadProc()
	{
		// Run loop so long as runWorkerFlag is signaled,
		// when runWorkerFlag is nonsignaled exit loop and
		// let thread finish
		while (runWorkerFlag.WaitOne(0))
		{
			// Do some work here
			Console.WriteLine("Worker thread with ID {0} running.", Thread.CurrentThread.ManagedThreadId);
			Thread.Sleep(3000);
		}
	}
}

Open in new window

0
 
LVL 33

Expert Comment

by:Todd Gerbert
ID: 34872258
I made a typo, line 92 should be if (disposing), also (if you use a Collection<T>) make sure you override ClearItems() as well.
0
 

Author Comment

by:brenlex
ID: 34929607
Thanks tgerbert, but my MyList object is already an instance of an existing threadsafe class which encapsulates an arraylist.  I have gone for the option of using ManualResetEvent to stop the thread, which in turn reports via callback when gracefully stopped, allowing me to destroy MyMonitord instance.

I shall try out your recommended method in the near future (for a similar project) though.  Hence point split.

Many thanks.
0

Featured Post

What Security Threats Are You Missing?

Enhance your security with threat intelligence from the web. Get trending threat insights on hackers, exploits, and suspicious IP addresses delivered to your inbox with our free Cyber Daily.

Join & Write a Comment

Suggested Solutions

Title # Comments Views Activity
asp.net bundle 8 36
Long URL in SMS 6 24
Red error squiggly on vb.net 7 12
Iterate two lists and remove inactive 11 35
Software development teams often use in-memory caches to improve performance. They want to speed up access to, or reduce load on, a backing store (database, file system, etc.) by keeping some or all of the data in memory.   You should implement a …
It was really hard time for me to get the understanding of Delegates in C#. I went through many websites and articles but I found them very clumsy. After going through those sites, I noted down the points in a easy way so here I am sharing that unde…
Internet Business Fax to Email Made Easy - With eFax Corporate (http://www.enterprise.efax.com), you'll receive a dedicated online fax number, which is used the same way as a typical analog fax number. You'll receive secure faxes in your email, fr…
Polish reports in Access so they look terrific. Take yourself to another level. Equations, Back Color, Alternate Back Color. Write easy VBA Code. Tighten space to use less pages. Launch report from a menu, considering criteria only when it is filled…

759 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

20 Experts available now in Live!

Get 1:1 Help Now