views:

410

answers:

7

I would like to start x number of threads from my .NET application, and I would like to keep track of them as I will need to terminate them manually or when my application closes my application later on.

Example ==> Start Thread Alpha, Start Thread Beta .. then at any point in my application I should be able to say Terminate Thread Beta ..

What is the best way to keep track of opened threads in .NET and what do I need to know ( an id ? ) about a thread to terminate it ? Sample code, tutorial would be helpful.

+1  A: 

Depends on how sophisticated you need it to be. You could implement your own type of ThreadPool with helper methods etc. However, I think its as simple as just maintaining a list/array and adding/removing the threads to/from the collection accordingly.

You could also use a Dictionary collection and use your own type of particular key to retrieve them i.e. Guids/strings.

James
+1  A: 

After creating your thread, you can set it's Name property. Assuming you store it in some collection you can access it conveniently via LINQ in order to retrieve (and abort) it:

var myThread = (select thread from threads where thread.Name equals "myThread").FirstOrDefault();
if(myThread != null)
    myThread.Abort();
Manu
+1  A: 

Wow, there are so many answers..

  1. You can simply use an array to hold the threads, this will only work if the access to the array will be sequantial, but if you'll have another thread accessing this array, you will need to synchronize access
  2. You can use the thread pool, but the thread pool is very limited and can only hold fixed amount of threads.
  3. As mentioned above, you can create you own thread pool, which in .NET v4 becomes much easier with the introduction of safe collections.
  4. you can manage them by holding a list of mutex object which will determine when those threads should finish, the threads will query the mutex each time they run before doing anything else, and if its set, terminate, you can manage the mutes from anywhere, and since mutex are by defenition thread-safe, its fairly easy..

i can think of another 10 ways, but those seems to work. let me know if they dont fit your needs.

MindFold
+2  A: 

You can create a Dictionary of threads and assign them id's, like:

Dictionary<string, Thread> threads = new Dictionary<string, Thread>();
for(int i = 0 ;i < numOfThreads;i++)
{
    Thread thread = new Thread(new ThreadStart(MethodToExe));
    thread.Name = threadName; //Any name you want to assign
    thread.Start(); //If you wish to start them straight away and call MethodToExe
    threads.Add(id, thread);
}

If you don't want to save threads against an Id you can use a list and later on just enumerate it to kill threads.

And when you wish to terminate them, you can abort them. Better have some condition in your MethodToExe that allows that method to leave allowing the thread to terminate gracefully. Something like:

void MethodToExe()
{
   while(_isRunning)
   {
      //you code here//
      if(!_isRunning)
      {
          break;
      }
      //you code here//
   }
}

To abort you can enumerate the dictionary and call Thread.Abort(). Be ready to catch ThreadAbortException

cornerback84
@cornerback84 I would advise against the use of Thread.Abort()... it's better to set the thread to background.
Lirik
Yes, but I was merely showing how to do it. Thats why I suggested him to have some condition in which he can abort thread. It can be that, or any exception like SocketException at which one can exit the methdo
cornerback84
+2  A: 

I asked a similar questions and received a bunch of good answers: http://stackoverflow.com/questions/2314861/shutting-down-a-multithreaded-application

Note: my question did not require a graceful exit, but people still recommended that I gracefully exit from the loop of each thread.

The main thing to remember is that if you want to avoid having your threads prevent your process from terminating you should set all your threads to background:

Thread thread = new Thread(new ThreadStart(testObject.RunLoop));
thread.IsBackground = true;
thread.start();

The preferred way to start and manage threads is in a ThreadPool, but just about any container out there can be used to keep a reference to your threads. Your threads should always have a flag that will tell them to terminate and they should continually check it.

Furthermore, for better control you can supply your threads with a CountdownLatch: whenever a thread is exiting its loop it will signal on a CountdownLatch. Your main thread will call the CountdownLatch.Wait() method and it will block until all the threads have signaled... this allows you to properly cleanup and ensures that all your threads have shutdown before you start cleaning up.

public class CountdownLatch
{
    private int m_remain;
    private EventWaitHandle m_event;

    public CountdownLatch(int count)
    {
        Reset(count);
    }

    public void Reset(int count)
    {
        if (count < 0)
            throw new ArgumentOutOfRangeException();
        m_remain = count;
        m_event = new ManualResetEvent(false);
        if (m_remain == 0)
        {
            m_event.Set();
        }
    }

    public void Signal()
    {
        // The last thread to signal also sets the event.
        if (Interlocked.Decrement(ref m_remain) == 0)
            m_event.Set();
    }

    public void Wait()
    {
        m_event.WaitOne();
    }
}

It's also worthy to mention that the Thread.Abort() method does some strange things:

When a thread calls Abort on itself, the effect is similar to throwing an exception; the ThreadAbortException happens immediately, and the result is predictable. However, if one thread calls Abort on another thread, the abort interrupts whatever code is running. There is also a chance that a static constructor could be aborted. In rare cases, this might prevent instances of that class from being created in that application domain. In the .NET Framework versions 1.0 and 1.1, there is a chance the thread could abort while a finally block is running, in which case the finally block is aborted.

The thread that calls Abort might block if the thread that is being aborted is in a protected region of code, such as a catch block, finally block, or constrained execution region. If the thread that calls Abort holds a lock that the aborted thread requires, a deadlock can occur.

Lirik
+3  A: 

You could save yourself the donkey work and use this Smart Thread Pool. It provides a unit of work system which allows you to query each thread's status at any point, and terminate them.

If that is too much bother, then as mentioned anIDictionary<string,Thread> is probably the simplest solution. Or even simpler is give each of your thread a name, and use an IList<Thread>:

public class MyThreadPool
{
    private IList<Thread> _threads;
    private readonly int MAX_THREADS = 25;

    public MyThreadPool()
    {
        _threads = new List<Thread>();
    }

    public void LaunchThreads()
    {
        for (int i = 0; i < MAX_THREADS;i++)
        {
            Thread thread = new Thread(ThreadEntry);
            thread.IsBackground = true;
            thread.Name = string.Format("MyThread{0}",i);

            _threads.Add(thread);
            thread.Start();
        }
    }

    public void KillThread(int index)
    {
        string id = string.Format("MyThread{0}",index);
        foreach (Thread thread in _threads)
        {
            if (thread.Name == id)
                thread.Abort();
        }
    }

    void ThreadEntry()
    {

    }
}

You can of course get a lot more involved and complicated with it. If killing your threads isn't time sensitive (for example if you don't need to kill a thread in 3 seconds in a UI) then a Thread.Join() is a better practice.

And if you haven't already read it, then Jon Skeet has this good discussion and solution for the "don't use abort" advice that is common on SO.

Chris S
+1  A: 

As you start each thread, put it's ManagedThreadId into a Dictionary as the key and the thread instance as the value. Use a callback from each thread to return its ManagedThreadId, which you can use to remove the thread from the Dictionary when it terminates. You can also walk the Dictionary to abort threads if needed. Make the threads background threads so that they terminate if your app terminates unexpectedly.

You can use a separate callback to signal threads to continue or halt, which reflects a flag set by your UI, for a graceful exit. You should also trap the ThreadAbortException in your threads so that you can do any cleanup if you have to abort threads instead.

ebpower