Question

Je ne suis pas sûr que c'est le forum approprié pour ce type de question, mais je suis en train d'essayer de trouver un bug, je ne peux pas reproduis dans un service Web à l'aide d'un vidage de la mémoire et je pense que je pose une question précise, je avez besoin d'aide, que Je pense que quelqu'un pourrait avoir une entrée sur.

L'analyse d'un vidage de la mémoire en utilisant WinDbg Je trouve aprox 75000 ThreadAbortExceptions en mémoire, et ils proviennent tous d'ici:

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

Ils sont tous créés dans un très court laps de temps, lorsque l'application tente de décharger sa appdomain (IIS ferme vers le bas).

Ce que je ne peux pas savoir est en ce moment comment il est possible de soulever tant de ThreadAbortExceptions? Si un départ volontaire de fil, est-il possible qu'il peut soulever plus d'un? Si quelqu'un peut donner une indication quant à la raison pour laquelle tant d'exceptions de ce type peuvent exister? D'après ce que je peux voir il y a environ 20 threads max est ce processus, et le threadpool lui-même n'a qu'un seul fil (!) Lorsque cela se produit.

La classe CustomThreadPool vient de cet article: 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;
    }
}
Était-ce utile?

La solution

Il est possible d'attraper puis réinitialiser un ThreadAbortException en utilisant Thread.ResetAbort . Ainsi, un seul fil pourrait avoir fait beaucoup de ces exceptions lancées à ce sujet.

Par exemple, si vous appelez Response.Redirect(url, true) dans ASP.NET, il abandonnera le fil en cours, puis annuler l'abandon plus haut.

Je ne sais pas ce qui explique tout à fait votre situation, mais il est intéressant de regarder. Sinon, est quelque chose d'essayer de recréer le pool de threads quand il « se bloque » en raison du domaine de l'application Déchargement?

EDIT: Pour répondre à votre commentaire: selon le AppDomain.Unload documentation :

  

Les fils de domaine sont terminées   en utilisant la méthode Abort, qui jette un   ThreadAbortException dans le fil.   Bien que le fil doit se terminer   rapidement, il peut continuer à exécuter   pour une quantité imprévisible de temps   une clause finally.

Fondamentalement, les fils sont précisément avortés parce que votre appdomain est déchargé.

Autres conseils

Faire un Response.Redirect ( "~ / Somewhere.aspx") provoque parfois un ThreadAbortException si le thread courant (par défaut) n'a pas fini de l'exécution encore.

Vous pouvez éviter cela en utilisant la méthode de redirection surchargée.

Response.Redirect("~/Somewhere.aspx", false);
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top