启动多个线程并从我的.NET应用程序中跟踪它们

时间:2010-03-01 13:40:12

标签: c# multithreading

我想从我的.NET应用程序中启动x个线程,我想跟踪它们,因为我需要手动终止它们,或者我的应用程序稍后关闭我的应用程序。

示例==>启动线程Alpha,启动线程测试..然后在我的应用程序的任何点,我应该能够说终止线程测试..

跟踪.NET中打开的线程的最佳方法是什么?我需要知道什么(一个id?)关于终止它的线程? 示例代码,教程会有所帮助。

7 个答案:

答案 0 :(得分:15)

你可以节省自己的驴工作并使用 Smart Thread Pool 。它提供了一个工作单元系统,允许您在任何时候查询每个线程的状态,并终止它们。

如果这太麻烦了,那么提到IDictionary<string,Thread>可能是最简单的解决方案。或者更简单的是为每个线程命名,并使用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()
    {

    }
}

你当然可以更多地参与其中并使其复杂化。如果杀死你的线程不是时间敏感的(例如,如果你不需要在UI中3秒内杀死一个线程),那么Thread.Join()是一种更好的做法。

如果你还没有读过它,那么Jon Skeet this good discussion and solution就那些在SO上常见的“不要使用中止”的建议而言。

答案 1 :(得分:3)

你可以创建一个线程词典并为它们分配id,如:

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);
}

如果你不想针对Id保存线程,你可以使用一个列表,稍后只需枚举它就可以杀死线程。

当您希望终止它们时,您可以中止它们。最好在MethodToExe中有一些允许该方法允许线程正常终止的条件。类似的东西:

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

要中止,您可以枚举字典并致电Thread.Abort()。准备好抓住ThreadAbortException

答案 2 :(得分:3)

我问过类似的问题并得到了很多好的答案:Shutting down a multithreaded application

注意:我的问题不需要优雅退出,但人们仍然建议我优雅地退出每个线程的循环。

要记住的主要事情是,如果你想避免线程阻止你的进程终止,你应该将所有线程设置为后台:

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

启动和管理线程的首选方法是ThreadPool,但几乎任何容器都可以用来保存对线程的引用。你的主题应该总是有一个标志,告诉他们终止,他们应该不断检查它。

此外,为了更好地控制,您可以为线程提供CountdownLatch:当线程退出其循环时,它将在CountdownLatch上发出信号。您的主线程将调用CountdownLatch.Wait()方法,它将阻塞,直到所有线程都已发出信号...这样您就可以正确清理并确保在开始清理之前所有线程都已关闭。

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();
    }
}

值得一提的是,Thread.Abort()方法做了一些奇怪的事情:

  

当一个线程调用Abort时,   效果类似于抛出一个   例外; ThreadAbortException   立即发生,结果是   可预测的。但是,如果一个线程   在另一个线程上调用Abort ,.   中止任何代码都会中断   运行。还有一个机会   静态构造函数可以中止。   在极少数情况下,这可能会阻止   该类的实例   在该应用程序域中创建。在   .NET Framework版本1.0和   1.1,有一个机会线程可以在最后一个块时中止   运行,在这种情况下终于   块被中止。

     

调用Abort的线程可能   阻止正在进行的线程   流产是在受保护的地区   代码,例如catch块,最后   阻止或约束执行   区域。如果是调用Abort的线程   持有一个被中止线程的锁   要求,可能会发生僵局。

答案 3 :(得分:2)

创建线程后,您可以设置它的Name属性。假设您将它存储在某个集合中,您可以通过LINQ方便地访问它以便检索(并中止)它:

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

答案 4 :(得分:1)

取决于您需要它的复杂程度。您可以使用辅助方法等实现自己的ThreadPool类型。但是,我认为它就像维护列表/数组并相应地向集合中添加/删除线程一样简单。

您还可以使用Dictionary集合并使用您自己的特定键类型来检索它们,即Guids / strings。

答案 5 :(得分:1)

哇,答案太多了。

  1. 你可以简单地使用一个数组来保存线程,这只有在对数组的访问是sequantial时才有效,但如果你有另一个线程访问这个数组,你将需要同步访问
  2. 您可以使用线程池,但线程池非常有限,只能容纳固定数量的线程。
  3. 如上所述,您可以创建自己的线程池,通过引入安全集合,可以更轻松地在.NET v4中使用它。
  4. 您可以通过保存互斥对象列表来管理它们,这将确定这些线程何时应该完成,线程将在每次运行之前查询互斥锁,然后执行其他操作,如果它设置了,则终止,您可以管理静音从任何地方,因为互斥是通过防御线程安全的,它相当容易..
  5. 我可以想到另外10种方法,但这些似乎有效。如果他们不符合您的需求,请告诉我。

答案 6 :(得分:1)

当你启动每个线程时,将它的ManagedThreadId作为键放入Dictionary中,将线程实例作为值。使用每个线程的回调来返回其ManagedThreadId,您可以使用该ManagedThreadId在终止时从Dictionary中删除该线程。如果需要,您还可以使用Dictionary来中止线程。使线程成为后台线程,以便在应用程序意外终止时终止它们。

您可以使用单独的回调来指示线程继续或暂停,这反映了UI设置的标志,以便正常退出。您还应该在线程中捕获ThreadAbortException,以便在必须中止线程时可以进行任何清理。