Hi
I have written a VB .NET app, which uses several threads. I thought
that when the user closes the main window (when MainForm.closed event
occures, and I call application.exit) all running threads must abort,
but to my great surprise, running threads do not stop when
application.exit is called. So I (or the users) have to stop threads
using Ctrl-Alt-Del.
Is there a way to stop ALL threads with a single instruction, without
having to run Thread.abort on each single thread?
thnx in advance,
and sorry for grammatical errors.
As Codemonkey said - foreground threads (which are the default type)
will not exit until they have been aborted or completed - and an
application will not exit until all foreground threads have exited.
It is possible to set the IsBackground property, so that the thread will
be a background thread. Background threads will abort as soon as the
last foreground thread has exited - in other words, they won't keep the
application alive....
Personally, I don't like the idea of having threads forcibly closed at
the end of the application - so I tend not to use Background threads. I
have taken several approaches to this problem myself - but my current
solution I'm working on for simple threads is to inherit a worker thread
class from a class that looks like this... (Sorry for the C# code - but
that's what I do - it should be fairly easy to convert this to VB.NET
though
using System;
using System.Threading;
namespace FireAnt.Threading
{
public abstract class WorkerThreadBase : IDisposable
{
private Thread worker;
private ManualResetEvent waitHandle;
private object terminateLock;
private bool terminate;
// make sure that derived classes call one of the
// defined constructors
private WorkerThreadBase() {}
// various constructors
public WorkerThreadBase(string name) : this(name, false, ApartmentState.MTA) {}
public WorkerThreadBase(string name, bool autoStart) : this(name, autoStart, ApartmentState.MTA) {}
public WorkerThreadBase(string name, ApartmentState apartmentState) : this(name, false, apartmentState) {}
// this is the bad boy!
public WorkerThreadBase(string name, bool autoStart, ApartmentState apartmentState)
{
if (name != null && name.Length > 0 )
{
// create some internal objects
this.waitHandle = new ManualResetEvent(false);
this.terminateLock = new object();
// create a new thread and set some initial defaults.
this.worker = new Thread(new ThreadStart(this.ThreadMethod));
this.worker.Name = name;
this.worker.ApartmentState = apartmentState;
if (autoStart)
{
this.Start();
}
}
else
{
throw new ArgumentException("Name can not be null or empty", "name");
}
}
~WorkerThreadBase()
{
this.Stop(true);
this.waitHandle.Close();
}
/// <summary>
/// Get/Set the value of the threads name
/// </summary>
public string Name
{
get
{
return worker.Name;
}
set
{
worker.Name = value;
}
}
public WaitHandle WaitHandle
{
get
{
return this.waitHandle;
}
}
public virtual void Start()
{
this.worker.Start();
}
public virtual void Stop(bool wait)
{
if (this.worker.IsAlive)
{
this.Terminate = true;
if (wait)
{
this.worker.Join();
}
}
}
protected bool Terminate
{
get
{
bool result = false;
// create a criticle section here...
Monitor.Enter(this.terminateLock);
result = this.terminate;
Monitor.Exit(this.terminateLock);
return result;
}
set
{
// create a criticle section here...
Monitor.Enter(this.terminateLock);
this.terminate = value;
Monitor.Exit(this.terminateLock);
}
}
private void ThreadMethod()
{
try
{
// call the work method...
this.Work();
}
catch
{
// TODO: RAISE AN EVENT?
}
finally
{
// signal that we are teminating...
this.waitHandle.Set();
}
}
protected abstract void Work();
#region IDisposable Members
public void Dispose()
{
this.Stop(true);
this.waitHandle.Close();
GC.SuppressFinalize(this);
}
#endregion
}
}
This is still a work in progress, so I haven't worked out all the
details yet. It is sort of a starting point for a simplfied threading
framework. That's the reason to force the name for the thread. I'm
planning a collection class that probably will inherit from
DictionaryBase that will make management of groups of threads a little
simpler
I got the idea for the class from an article I read
a couple of weeks ago - unfortunately, I can't remember where.
Anway the idea is that you can then use it like this:
public class Worker : WorkerThreadBase
{
// define a constructor
Worker(string name, bool autoStart) : base(name, autoStart)
{
}
// override the work method
public override void Work()
{
int i = 0;
while (!this.Terminate)
{
Console.WriteLine("{0} - {1}", this.Name, i);
Thread.Sleep(100);
i++;
}
}
public static void Main()
{
// create and start the threads
Worker w1 = new Worker("John", true);
Worker w2 = new Worker("Mary", true);
// wait for a while
Console.ReadLine();
// stop them async
w1.Stop(false);
w2.Stop(false);
// wait for all threads to complete
WaitHandle.WaitAll(new WaitHandle[] {w1.WaitHandle, w2.WaitHandle});
// dispose unmanaged resources.
w1.Dispose();
w2.Dispose();
}
}
Anyway, maybe this will give you a starting point for your own threading
framework.