Domanda

Non sono sicuro questo è il forum corretto per questo tipo di domanda, ma al momento sto cercando di trovare un bug non posso riprodurre in un servizio Web utilizzando un dump della memoria e penso di avere una specifica domanda di aiuto di cui ho bisogno di, che credo che qualcuno potrebbe avere qualche input su.

Analisi di un dump di memoria utilizzando WinDbg trovo aprox 75000 ThreadAbortExceptions in memoria, e tutti hanno origine da qui:

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

Essi sono tutti creati in un brevissimo periodo di tempo, quando l'applicazione tenta di scaricare il suo appdomain (IIS sta chiudendo).

Quello che Non riesco a capire in questo momento è come la sua possibile raccogliere tante ThreadAbortExceptions? Se un thread si chiude, c'è qualche modo si può sollevare più di uno? Se chiunque può dare alcun suggerimento sul motivo per cui possono esistere tante eccezioni di questo tipo? Da quello che posso vedere ci sono circa 20 le discussioni max è questo processo, e il pool di thread in sé ha un solo filo (!) Quando ciò si verifica.

La classe CustomThreadPool viene da questo articolo: 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;
    }
}
È stato utile?

Soluzione

E 'possibile cattura e poi reimpostare una ThreadAbortException utilizzando Thread.ResetAbort . Quindi un singolo thread in realtà potrebbe avere molte di queste eccezioni generate su di esso.

Ad esempio, se si chiama Response.Redirect(url, true) in ASP.NET, sarà interrompere il thread corrente e quindi annullare l'interruzione più in alto.

Non sono sicuro che questo bel spiega la vostra situazione, ma vale la pena guardare. In alternativa, è qualcosa cercando di ricreare il pool di thread quando si "blocca" a causa del dominio applicazione viene scaricato?

EDIT: Per rispondere a un commento: come per il documentazione AppDomain.Unload :

  

I fili nel dominio sono terminati   utilizzando il metodo Abort, che genera un   ThreadAbortException nel thread.   Sebbene il filo deve terminare   tempestivamente, può continuare l'esecuzione   per una quantità imprevedibile di tempo in   una clausola finally.

In linea di massima i fili vengono interrotte proprio perché il tuo dominio di applicazione viene scaricata.

Altri suggerimenti

Fare un Response.Redirect ( "~ / Somewhere.aspx") a volte provoca un ThreadAbortException se l'attuale (default) thread ha ancora esecuzione non finito.

È possibile evitare questo utilizzando il metodo di reindirizzamento sovraccarico.

Response.Redirect("~/Somewhere.aspx", false);
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top