2010-02-22 241 views
8

我想为我的C#应用​​程序编写一个ThreadManager。我创建了几个线程:
我的文本编写器的一个线程。
一个线程监视一些统计信息。
多线程执行大量计算(每个核心最多4个线程,并且我在2x四核服务器上运行我的应用程序)。关闭多线程应用程序

我的应用程序一次最多可以运行24小时,因此所有线程都会在开始时创建,并且始终保持应用程序运行的整个时间。

我希望有一个地方可以“注册”我所有的步骤,当应用程序关闭时,我只需调用一个方法,它会遍历所有已注册的线程并关闭它们。

出于这个目的,我设计了以下类:

public class ThreadManager 
{ 
    private static Object _sync = new Object(); 
    private static ThreadManager _instance = null; 
    private static List<Thread> _threads; 
    private ThreadManager() 
    { 
     _threads = new List<Thread>(); 
    } 

    public static ThreadManager Instance 
    { 
     get 
     { 
      lock (_sync) 
      { 
       if (_instance == null) 
       { 
        _instance = new ThreadManager(); 
       } 
      } 
      return _instance; 
     } 
    } 

    public void AddThread(Thread t) 
    { 
     lock (_sync) 
     { 
      _threads.Add(t); 
     } 
    } 

    public void Shutdown() 
    { 
     lock (_sync) 
     { 
      foreach (Thread t in _threads) 
      { 
       t.Abort(); // does this also abort threads that are currently blocking? 
      } 
     } 
    } 
} 

我想确保我的所有线程都杀了那么应用程序可以正常关闭,并在某些运算的中间关停就好了太。我应该知道这里有什么吗?鉴于我的情况,这种方法是否合适?

+0

哇! Lot很好的答案...现在很难选择。因为他是第一个,所以我给了Nate复选标记,把它从他身上拿走是不公平的。让我们看看这些票是怎么说的。我从你的答案中得到一些有用的东西,所以请投票支持你的心。 – Kiril 2010-02-22 23:06:41

+0

线程池线程的默认行为与我所建议的相同。如果你不关心你的线程没有完成,我的是最简单的解决方案。很明显,其他答案在管理线程方面做得很好,但是你明确指出在计算过程中杀死线程是很好的。 – 2010-02-22 23:14:52

+0

我同意你的看法;),我不打算取消选中标记,因为这样做不公平,你给了我最准确,最快速,最简单的答案......我希望其他人得到他们的公平信用,所以我希望每个人都为所有的好答案投票。 – Kiril 2010-02-23 00:04:27

回答

16

如果将线程设置为后台线程,它们将在应用程序关闭时被终止。

myThread.IsBackground = true; 

显然,如果您需要线程在关机前完成,这不是您想要的解决方案。

+0

谢谢Nate,当我创建它们时,我将所有线程设置为后台线程......这是否意味着我不需要中止它们呢? – Kiril 2010-02-22 22:56:20

+0

是的,如果它们被设置为后台线程,关闭应用程序将强制线程退出。 http://msdn.microsoft.com/en-us/library/system.threading.thread.isbackground.aspx – 2010-02-22 22:57:58

14

中止线程是你所做的当所有其他都失败。这是一件危险的事情,你应该只做最后的手段。执行此操作的正确方法是制作线程逻辑,以便每个工作线程在主线程向其发出关闭命令时快速正确地响应。

巧合的是,这是我本周博客的主题。

http://blogs.msdn.com/ericlippert/archive/2010/02/22/should-i-specify-a-timeout.aspx

+1

线程中止异常在执行finally块期间被阻止对我而言是新的。感谢您添加此。 – 2010-02-22 23:13:47

+0

@ fatcat1111:事实上,没有任何事情可以保证中止的线程将因中止而停止。只是另一个避免Thread.Abort的原因;它既危险又不可靠。 – 2010-02-22 23:37:49

+0

同意,绝对是最后的选择。 – 2010-02-23 00:54:54

3

如果什么AddThread您关闭正在运行时叫什么名字?

当关闭完成时,在AddThread中等待的线程将向集合中添加一个新线程。这可能会导致您的应用程序停滞不前。

添加一个您在关机时只设置的布尔标志,以防止出现这种情况。

bool shouldGoAway = false; 
public void AddThread(Thread t) 
{ 
    lock (_sync) 
    { 
     if(! shouldGoAway) 
      _threads.Add(t); 
    } 
} 

public void Shutdown() 
{ 
    lock (_sync) 
    { 
     shouldGoAway = true; 
     foreach (Thread t in _threads) 
     { 
      t.Abort(); // does this also abort threads that are currently blocking? 
     } 
    } 

此外,你不应该使用静态成员 - 没有理由因为你有你的单身实例。

.Abort()不会中止在非托管空间中阻塞的线程。所以如果你这样做,你需要使用其他一些机制。

1

如果你不关心的工作线程状态,则可以遍历_Thread并中止:

void DieDieDie() 
{ 
    foreach (Thread thread in _thread) 
    { 
     thread.Abort(); 
     thread.Join(); // if you need to wait for the thread to die 
    } 
} 

在你的情况,你可能只需要中止所有这些,关机,因为他们只是在做计算。但是,如果您需要等待数据库写入操作或需要关闭非托管资源,那么您需要捕获ThreadAbortException或指示线程自我牺牲自己。

0

你想延迟线程取消,这基本上意味着线程终止自己,而不是线程管理器异步取消线程,这是更加不明确和危险。

我想要比直接终止更优雅地处理线程取消,您可以使用由线程之外的事件触发的信号处理程序 - 也许由您的线程管理器来处理。