0

我不确定这是此类问题的正确论坛,但我目前正在尝试使用内存转储查找无法在 Web 服务中重现的错误,并且我认为我有一个需要帮助的特定问题,我认为有人可能有一些输入。

使用 WinDbg 分析内存转储我在内存中发现了 aprox 75000 ThreadAbortExceptions,它们都来自这里:

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

它们都是在很短的时间内创建的,当时应用程序正在尝试卸载其 appdomain(IIS 正在关闭)。

我现在想不通的是怎么可能引发这么多的 ThreadAbortExceptions?如果一个线程退出,有什么方法可以引发多个?如果有人能给出任何提示,为什么会存在这么多这种类型的例外?据我所知,这个进程最多有 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;
    }
}
4

2 回答 2

1

可以捕获然后重置ThreadAbortExceptionusing Thread.ResetAbort。因此,单个线程实际上可能会引发许多此类异常。

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

我不确定这是否能完全解释您的情况,但值得一看。或者,当应用程序域被卸载而“崩溃”时,是否试图重新创建线程池?

编辑:回复您的评论:根据AppDomain.Unload文档:

域中的线程使用 Abort 方法终止,该方法在线程中引发 ThreadAbortException。尽管线程应该立即终止,但它可以在 finally 子句中继续执行不可预测的时间。

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

于 2010-06-21T08:29:48.370 回答
0

如果当前(默认)线程尚未完成执行,则执行 Response.Redirect("~/Somewhere.aspx") 有时会导致 ThreadAbortException。

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

Response.Redirect("~/Somewhere.aspx", false);
于 2010-06-21T08:52:08.477 回答