由于异常,代码在线程池中执行了无限次

时间:2011-10-05 18:26:25

标签: asp.net multithreading threadpool asp.net-4.0

我听说在asp.net中使用ThreadPool很糟糕,但是我已经用它来教育自己。我的目标是确定是否触发了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 :(得分:0)

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。