2010-06-21 144 views
0

林不知道这是这类问题的正确论坛,但我目前正试图找到一个错误,我不能在使用内存转储的Web服务中重现,我想我有一个具体的问题,我需要帮助,我认为有人可能会有一些意见。线程是否可以抛出多个ThreadAbortException异常?

分析使用的WinDbg我发现aprox的内存75000个ThreadAbortExceptions,他们都从这里起源内存转储:

at System.Threading.WaitHandle.WaitOne(Int64 timeout Boolean exitContext) 
at MyNameSpace.CustomThreadPool.Run() 

它们在一段很短的时期都创造,当应用程序试图卸载它的appdomain(IIS正在关闭)。

我现在无法弄清楚它是如何可能引发这么多的ThreadAbortException?如果一个线程退出,有什么方法可以提高多个?如果任何人都可以提出任何暗示,为什么会有这么多的这种类型的例外存在?从我所看到的最多有20个线程是这个进程,并且线程池本身只有一个(!)线程发生这种情况。

的CustomThreadPool类来自这篇文章: http://msdn.microsoft.com/en-us/magazine/cc163851.aspx

public sealed class CustomThreadPool : IDisposable 
{ 
    private Semaphore _workWaiting; 
    private Queue<WaitQueueItem> _queue; 
    private List<Thread> _threads; 

    public CustomThreadPool(int numThreads) 
    { 
     if (numThreads <= 0) 
      throw new ArgumentOutOfRangeException("numThreads"); 

     _threads = new List<Thread>(numThreads); 
     _queue = new Queue<WaitQueueItem>(); 
     _workWaiting = new Semaphore(0, int.MaxValue); 

     for (int i = 0; i < numThreads; i++) 
     { 
      Thread t = new Thread(Run); 
      t.IsBackground = true; 
      _threads.Add(t); 
      t.Start; 
     } 
    } 

    public void Dispose() 
    { 
     if (_threads != null) 
     { 
      _threads.ForEach(delegate(Thread t) { t.Interrupt(); }); 
      _threads = null; 
     } 
    } 

    public void QueueUserWorkItem(WaitCallback callback, object state) 
    { 
     if (_threads == null) 
      throw new ObjectDisposedException(GetType().Name); 
     if (callback == null) throw new ArgumentNullException("callback"); 

     WaitQueueItem item = new WaitQueueItem(); 
     item.Callback = callback; 
     item.State = state; 
     item.Context = ExecutionContext.Capture(); 

     lock(_queue) _queue.Enqueue(item); 
     _workWaiting.Release(); 
    } 

    private void Run() 
    { 
     try 
     { 
      while (true) 
      { 
       _workWaiting.WaitOne(); 
       WaitQueueItem item; 
       lock(_queue) item = _queue.Dequeue(); 
       ExecutionContext.Run(item.Context, 
        new ContextCallback(item.Callback), item.State); 
      } 
     } 
     catch(ThreadInterruptedException){} 
    } 

    private class WaitQueueItem 
    { 
     public WaitCallback Callback; 
     public object State; 
     public ExecutionContext Context; 
    } 
} 

回答

1

有可能赶上,然后使用Thread.ResetAbort重置ThreadAbortException。所以一个线程实际上可能会有很多这样的异常抛出。

例如,如果您在ASP.NET中调用Response.Redirect(url, true),它将中止当前线程,然后取消较高的中止。

我不确定这是否可以解释您的情况,但值得一看。或者,是否因尝试卸载应用程序域而导致线程池“崩溃”时尝试重新创建线程池?

编辑:为了回答您的评论:依照AppDomain.Unload文档:

域的线程使用Abort方法,其全中,线程 ThreadAbortException终止 。 虽然线程应该立即终止 ,但它可以在 finally子句中继续执行 不可预知的时间量。

基本上线程正在中止,正是因为你的appdomain被卸载。

+0

非常感谢那个输入,我不知道Thread.Abort! 但是,我无法在我控制的代码中找到任何用法。框架可以自己做这件事吗? 我看了Respose.Redirect,Response.End和Server.Transfer,但我找不到任何用法。 娱乐是我要去看的东西,谢谢。 – MatteS 2010-06-21 08:35:04

+0

如果每隔x分钟重新创建一个池,从而创建一个新线程,那么最大线程可以存在,还是有可能拥有多达75000个线程?我目前正在看一些代码,可能会建议以定时间隔进行娱乐。 – MatteS 2010-06-21 08:45:16

+0

@MatteS:看我的编辑。我怀疑你有75000线程 - 我怀疑是有什么响应线程中止再次启动它,然后AppDomain.Unload重新中止它等。 – 2010-06-21 08:48:04

0

如果当前(缺省)线程尚未完成执行,则执行Response.Redirect(“〜/ Somewhere.aspx”)有时会导致ThreadAbortException。

您可以通过使用重载重定向方法来防止这种情况。

Response.Redirect("~/Somewhere.aspx", false);