代码之家  ›  专栏  ›  技术社区  ›  G-Man

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

  •  17
  • G-Man  · 技术社区  · 15 年前

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

    跟踪.NET中打开的线程的最佳方法是什么?我需要知道什么(id?)关于终止它的线程?

    7 回复  |  直到 4 年前
        1
  •  16
  •   Chris S    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()是更好的做法。

    this good discussion and solution 对于“不要使用中止”的建议,这在SO上很常见。

        2
  •  4
  •   ata    15 年前

    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

        3
  •  3
  •   Community Mohan Dere    8 年前

    Shutting down a multithreaded application

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

    要记住的主要一点是,如果希望避免线程阻止进程终止,则应将所有线程设置为后台:

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

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

    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异常 立即发生,结果是 可预测的但是,如果一个线程 在另一个线程上调用中止 中止中断任何代码 跑步还有一种可能性是 在极少数情况下,这可能会阻止 在该应用程序域中创建。在里面 .NET Framework版本1.0和 在这种情况下 块被中止。

    调用Abort的线程可能 在的受保护区域中 区域如果调用中止的线程 如果需要,可能会发生死锁。

        4
  •  2
  •   Manu JCasso    15 年前

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

    var myThread = (select thread from threads where thread.Name equals "myThread").FirstOrDefault();
    if(myThread != null)
        myThread.Abort();
    
        5
  •  1
  •   MindFold    15 年前

    哇,有这么多答案。。

    1. 可以使用线程池,但线程池非常有限,只能容纳固定数量的线程。
    2. 如上所述,您可以创建自己的线程池,在.NETV4中,引入安全集合后,这将变得更加容易。
    3. 您可以通过保存一个mutex对象列表来管理它们,该列表将确定这些线程应该在何时完成,线程每次运行时都会在执行其他操作之前查询mutex,如果设置、终止mutex,您可以从任何地方管理mutex,而且由于mutex是由defenition线程安全的,因此非常简单。。

        6
  •  1
  •   James    15 年前

    取决于你需要它有多复杂。您可以使用helper方法等实现自己类型的线程池。但是,我认为这很简单,只需维护一个列表/数组,并相应地向集合中添加/删除线程即可。

    您还可以使用字典集合并使用自己的特定键类型来检索它们,即guid/字符串。

        7
  •  1
  •   Ed Power    15 年前

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

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