2010-03-01 31 views
16

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

例==>启动线程阿尔法,启动线程测试版..然后在我的应用程序的任何一点我应该可以说终止线程测试版..

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

回答

14

你可以节省自己的驴工作,并使用这个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() 
    { 

    } 
} 

当然,你可以得到很多非常棘手且复杂吧。如果杀死你的线程不是时间敏感的(例如,如果你不需要在3秒内杀死一个线程),那么Thread.Join()是一个更好的做法。

如果您还没有阅读过,那么Jon Skeet的this good discussion and solution针对SO上常见的“不使用中止”建议。

+0

我得到了一个问题,关于void ThreadEntry(),一旦我们在线程起点的主应用程序中创建了多个线程,我们就可以启动根据分配的线程数,该线程上的任何其他应用程序。 – shawn

1

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

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

2

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

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

哇,有这么多的答案..

  1. 您可以简单地使用一个数组来存放这些线程,这只有在数组访问权限的时候才起作用,但如果你有另一个线程访问这个数组,你将需要同步访问
  2. 你可以使用线程池,但是线程池非常有限,只能容纳固定数量的线程。
  3. 如上所述,您可以创建自己的线程池,通过引入安全集合,.NET v4中的线程池变得更容易。
  4. 你可以通过持有一个互斥对象列表来管理它们,它将确定这些线程何时应该完成,线程每次运行之前都会查询互斥量,然后执行其他操作,并且如果其设置,终止,您可以管理静音从任何地方,因为互斥体是由defenition线程安全的,它相当容易..

我可以想到另外10种方式,但这些似乎工作。让我知道他们是否不适合你的需求。

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

+0

@ cornerback84我建议不要使用Thread.Abort()...最好将线程设置为背景。 – Kiril

+0

是的,但我只是在展示如何去做。那就是为什么我建议他有一些他可以放弃线程的条件。它可能是这样的,或任何异常像SocketException一样可以退出methdo – ata

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的()方法做了一些奇怪的事情:

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

调用线程中止可能 块是否正被 中止线程处于的 代码,被保护的区域,例如一个catch块,最后 块,或约束的执行 区域。如果调用Abort 的线程持有中止线程 需要的锁定,则会发生死锁。

1

当你开始每个线程时,把它的ManagedThreadId放到一个字典中作为键值和线程实例值。使用来自每个线程的回调来返回其ManagedThreadId,您可以使用它从线程终止时从线程中删除该线程。如果需要,也可以使用Dictionary来中止线程。使线程后台线程,以便他们终止,如果你的应用程序意外终止。

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