Может ли поток когда-либо генерировать более одного исключения ThreadAbortException?
Я не уверен, что это правильный форум для такого типа вопросов, но в настоящее время я пытаюсь найти ошибку, которую не могу воспроизвести в веб-сервисе с использованием дампа памяти, и я думаю, что у меня есть конкретный вопрос, с которым мне нужна помощь, который я думаю, кто-то может иметь некоторый вклад на.
Анализируя дамп памяти с помощью WinDbg, я нахожу в памяти aprox 75000 ThreadAbortException, и все они происходят отсюда:
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 ответа
Можно поймать и затем сбросить ThreadAbortException
с помощью Thread.ResetAbort
, Таким образом, в одном потоке может быть много таких исключений.
Например, если вы звоните Response.Redirect(url, true)
в ASP.NET он прерывает текущий поток, а затем отменяет отмену выше.
Я не уверен, что это вполне объясняет вашу ситуацию, но на это стоит посмотреть. Кроме того, что-то пытается воссоздать пул потоков, когда он "падает" из-за выгрузки домена приложения?
РЕДАКТИРОВАТЬ: Чтобы ответить на ваш комментарий: согласно AppDomain.Unload
документация:
Потоки в домене завершаются с помощью метода Abort, который создает исключение ThreadAbortException в потоке. Хотя поток должен завершиться быстро, он может продолжать выполняться в течение непредсказуемого периода времени в предложении finally.
В основном потоки прерываются именно потому, что ваш домен приложений выгружается.
Выполнение Response.Redirect("~/Somewhere.aspx") иногда вызывает исключение ThreadAbortException, если текущий поток (по умолчанию) еще не завершил выполнение.
Вы можете предотвратить это, используя перегруженный метод перенаправления.
Response.Redirect("~/Somewhere.aspx", false);