Pregunta

No estoy seguro de que este es el foro adecuado para este tipo de pregunta, pero actualmente estoy tratando de encontrar un error que no puedo reproduzco en un servicio web utilizando un volcado de memoria y creo que tengo una pregunta que necesito ayuda específica, que creo que alguien pueda hacer un aporte sucesivamente.

Análisis de un volcado de memoria utilizando WinDbg encuentro aprox 75000 ThreadAbortExceptions en la memoria, y todos ellos se origino desde aquí:

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

Ellos son creados en un período muy corto de tiempo, cuando la aplicación está intentando descargar su dominio de aplicación (IIS está cerrando).

Lo que yo puedo imaginar en este momento es como su posible elevar tantas ThreadAbortExceptions? Si un hilo se cierra, ¿hay alguna manera se puede elevar más de uno? Si alguien puede dar alguna pista de por qué pueden existir tantas excepciones de este tipo? Por lo que puedo ver que hay sobre 20 hilos Max es este proceso, y el conjunto de subprocesos en sí tiene sólo una (!) Hilo cuando esto ocurre.

La clase CustomThreadPool proviene de este artículo: 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;
    }
}
¿Fue útil?

Solución

Es posible la captura y luego restablecer una ThreadAbortException usando Thread.ResetAbort . Por lo que un solo hilo en realidad podría tener muchas de estas excepciones producidas en él.

Por ejemplo, si se llama a Response.Redirect(url, true) en ASP.NET, se abortará el hilo actual y luego cancelar el aborto de más arriba.

No estoy seguro de esto bastante explica su situación, pero es digno de mirar. Por otra parte, es algo que intenta recrear el grupo de subprocesos cuando se descargaban se "bloquea" debido al dominio de aplicaciones?

EDIT: Para responder a su comentario: según el documentación AppDomain.Unload :

  

Los hilos en el dominio se terminan   utilizando el método Abort, que lanza una   ThreadAbortException en el hilo.   A pesar de que el hilo debe terminar   oportunamente, puede continuar con la ejecución   para una cantidad de tiempo impredecible en   un finalmente cláusula.

Básicamente las roscas están siendo abortados precisamente por su dominio de aplicación se está descargando.

Otros consejos

Haciendo un Response.Redirect ( "~ / Somewhere.aspx") a veces causa una ThreadAbortException si la corriente de rosca (por defecto) tiene la ejecución no ha terminado todavía.

Se puede evitar esto usando el método de redirección sobrecargado.

Response.Redirect("~/Somewhere.aspx", false);
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top