Может ли поток когда-либо генерировать более одного исключения ThreadAbortException? - PullRequest
0 голосов
/ 21 июня 2010

Я не уверен, что это правильный форум для такого типа вопросов, но я сейчас пытаюсь найти ошибку, которую не могу воспроизвести в веб-сервисе с помощью дампа памяти, и я думаю, что у меня есть конкретный вопрос, с которым мне нужна помощь, чтоЯ думаю, что кто-то может иметь некоторые входные данные.

Анализируя дамп памяти с помощью WinDbg, я нахожу в памяти aprox 75000 ThreadAbortExceptions, и все они происходят отсюда:

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

Все они созданы вочень короткий промежуток времени, когда приложение пытается выгрузить свой домен приложения (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;
    }
}

Ответы [ 2 ]

1 голос
/ 21 июня 2010

Можно перехватить и затем сбросить ThreadAbortException, используя Thread.ResetAbort. Таким образом, в одном потоке может быть много таких исключений.

Например, если вы вызовете Response.Redirect(url, true) в ASP.NET, он прервет текущий поток, а затем отменит отмену выше.

Я не уверен, что это вполне объясняет вашу ситуацию, но на это стоит посмотреть. Или же что-то пытается воссоздать пул потоков, когда он «падает» из-за выгрузки домена приложения?

РЕДАКТИРОВАТЬ: Чтобы ответить на ваш комментарий: в соответствии с AppDomain.Unload документация:

Потоки в домене прекращаются используя метод Abort, который бросает ThreadAbortException в потоке. Хотя поток должен прекратить быстро, он может продолжить выполнение на непредсказуемое количество времени в окончательное предложение.

В основном потоки прерываются именно потому, что ваш домен приложений выгружается.

0 голосов
/ 21 июня 2010

Выполнение Response.Redirect ("~ / Somewhere.aspx") иногда вызывает исключение ThreadAbortException, если текущий поток (по умолчанию) еще не завершил выполнение.

Вы можете предотвратить это, используя перегруженный метод перенаправления.

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