سؤال

لست متأكدًا من أن هذا هو المنتدى الصحيح لهذا النوع من الأسئلة ، لكنني أحاول حاليًا العثور على خطأ لا يمكنني إعادة إنتاجه في خدمة ويب باستخدام تفريغ الذاكرة وأعتقد أن لدي سؤالًا محددًا أحتاج إلى مساعدة فيه ، وأعتقد أن شخصًا ما قد يكون لديك بعض المدخلات على.

تحليل تفريغ الذاكرة باستخدام Windbg أجد aprox 75000 threadabortexceptions في الذاكرة ، وكلها تنشأ من هنا:

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

يتم إنشاؤها جميعًا في فترة زمنية قصيرة جدًا ، عندما يحاول التطبيق تفريغ AppDomain (يتم إغلاق IIS).

ما لا يمكنني اكتشافه الآن هو كيف من الممكن رفع عدد كبير من المواقف؟ إذا ترك موضوع ، هل هناك أي طريقة قد ترفع أكثر من واحد؟ إذا كان بإمكان أي شخص إعطاء أي تلميح حول سبب وجود العديد من الاستثناءات من هذا النوع؟ من ما أستطيع أن أرى أن هناك حوالي 20 موضوعًا كحد أقصى هو هذه العملية ، ويحتوي Threadpool نفسه على مؤشر ترابط واحد (!) عند حدوث ذلك.

تأتي فئة 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;
    }
}
هل كانت مفيدة؟

المحلول

من الممكن التقاط ثم إعادة تعيين أ ThreadAbortException استخدام Thread.ResetAbort. لذلك يمكن أن يكون لخيط واحد بالفعل العديد من الاستثناءات التي تم طرحها عليه.

على سبيل المثال ، إذا اتصلت Response.Redirect(url, true) في ASP.NET ، سيقوم بإحباط الخيط الحالي ثم إلغاء الإجهاض أعلى.

لست متأكدًا من أن هذا يفسر وضعك تمامًا ، لكن الأمر يستحق النظر إليه. بدلاً من ذلك ، هل هناك شيء يحاول إعادة إنشاء تجمع الخيوط عندما "يتعطل" بسبب تفريغ مجال التطبيق؟

تحرير: للرد على تعليقك: حسب AppDomain.Unload توثيق:

يتم إنهاء مؤشرات الترابط في المجال باستخدام طريقة الإحباط ، والتي ترمي مؤشر ترابط في الخيط. على الرغم من أنه يجب أن ينتهي الخيط على الفور ، إلا أنه يمكن أن يستمر في التنفيذ لفترة لا يمكن التنبؤ بها من الوقت في جملة أخيرًا.

في الأساس يتم إحباط الخيوط على وجه التحديد لأن appdomain الخاص بك يتم تفريغه.

نصائح أخرى

يؤدي القيام بالاستجابة. REDIRECT ("~/someute.aspx") في بعض الأحيان يتسبب في threadabortexception إذا لم ينته مؤشر الترابط الحالي (الافتراضي) بعد.

يمكنك منع ذلك باستخدام طريقة إعادة التوجيه الزائدة.

Response.Redirect("~/Somewhere.aspx", false);
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top