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



我听说在asp.net中使用ThreadPool是不好的,但是我使用它是为了自我教育。我的目标是确定Application_Error事件是否被触发(这是在Global.asax中处理的)-我的答案是:不,它没有被触发。

但是我发现了一些奇怪的事情。我编写的线程只是将任务排队到线程池中。这个任务的目的是随机抛出错误。但我注意到,我经常得到错误-数字超过了no。我把任务排了多少次。我所关心的另一个问题是,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");
        }
    }
}

您的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。

最新更新