Код выполняется бесконечно много раз в пуле потоков из-за исключения - PullRequest
0 голосов
/ 05 октября 2011

Я слышал, что использование ThreadPool в asp.net плохо, но я использовал его для обучения.Моя цель состояла в том, чтобы определить, было ли запущено событие Application_Error (которое обрабатывается в Global.asax) - мой ответ на этот вопрос: нет, оно не срабатывает.

Но я заметил нечто странное.Поток, который я написал, просто ставил задачи в очередь в пуле потоков.Задача была выбрасывать ошибки случайным образом.Но я заметил, что я часто получаю сообщение об ошибке - число превышает «нет».раз я поставил в очередь задачу.У меня отдельная проблема, даже System.Diagnostics.Trace.WriteLine() не регистрирует сообщения в моем окне вывода (Visual Studio).Почему это странное поведение?

using System;
using System.Threading;
namespace ThreadPoolDemo.Web
{
    public partial class _default : System.Web.UI.Page
    {
        protected void Page_Load(object sender, EventArgs e)
        {

        }

        protected void Button1_Click(object sender, EventArgs e)
        {
            Thread t = new Thread(createthreads);
            t.IsBackground = true;
            t.Start();
        }

        void createthreads()
        {
            Thread.Sleep(10 * 1000);
            int i;
            System.Diagnostics.Trace.WriteLine("Queueing items");
            for (i = 0; i < 1; i++)
                ThreadPool.QueueUserWorkItem(new WaitCallback(ErrorTask), null);
            System.Diagnostics.Trace.WriteLine("End Queueing items");
        }

        void ErrorTask(object obj)
        {
            Random generator = new Random();
            int value = generator.Next(1);            
            if (value == 0)
                throw new Exception("Sample exception thrown");
            else
                System.Diagnostics.Trace.WriteLine("Processed thread");
        }

    }
}

1 Ответ

0 голосов
/ 06 октября 2011

Есть две проблемы с вашим ErrorTask. Во-первых, вы инициализируете новый экземпляр Random каждый раз, когда вызывается метод. Конструктор Random по умолчанию запускает генератор случайных чисел со значением Environment.TickCount, которое, вероятно, будет одинаковым для последовательных потоков. Таким образом, вы получите одну и ту же случайную последовательность для нескольких потоков.

Тем не менее, большая проблема заключается в том, что generator.Next(1) будет всегда возвращать 0. Random.Next(int max) генерирует случайное число N, такое что 0 <= N < max. Таким образом, ваш ErrorTask сгенерирует исключение для каждого потока.

Я понятия не имею, как или почему было бы выбрасывать это исключение более одного раза за вызов ErrorTask. Это кажется невозможным.

Я бы предложил следующую модификацию:

private Random generator = new Random();

void ErrorTask(object obj)
{
    int value;
    lock (generator)
    {
        value = generator.Next(2);
    }
    if (value == 0)
        throw new Exception("Sample exception thrown");
    else
        System.Diagnostics.Trace.WriteLine("Processed thread");
}

generator теперь имеет область видимости класса и инициализируется только один раз. lock используется для предотвращения одновременной генерации номера несколькими потоками. Без блокировки генератор случайных чисел может быть поврежден, и он будет возвращать 0 при каждом вызове. И я изменил параметр на generator.Next на 2, чтобы вы могли получить числа 0 и 1.

...