【问题标题】:Code executed infinite times in threadpool because of exception由于异常,代码在线程池中执行了无限次
【发布时间】:2011-12-01 17:26:46
【问题描述】:

我听说在 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");
        }

    }
}

【问题讨论】:

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


    【解决方案1】:

    您的ErrorTask 有两个问题。第一个是每次调用该方法时都在初始化一个新的Random 实例。默认的Random 构造函数使用来自Environment.TickCount 的值作为随机数生成器的种子,这对于连续线程可能是相同的。因此,您将获得多个线程的相同随机序列。

    不过,更大的问题是generator.Next(1)总是返回 0。Random.Next(int max) 生成一个随机数 N,这样0 &lt;= N &lt; 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了。

    【讨论】:

    • 感谢您的信息。这很有帮助。您在 VS IDE 中尝试过吗?它发生在 IDE 中。但是,在 iis v5.1 上,我发现每次发生异常时,aspnet_wp.exe 进程都会死亡并以另一个进程 ID 重新出现。在事件日志中,有 4 个条目对应于一个异常,即我猜的第一个异常。我想这很糟糕,如果它发生在一个在网络服务器中维护会话数据的网站上......
    • @deostroll:我没有尝试运行您的代码。我的观察是基于检查代码。也许人们不鼓励在 asp.net 应用程序中使用线程池是有充分理由的。
    猜你喜欢
    • 2021-04-11
    • 2011-06-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-10-11
    • 1970-01-01
    相关资源
    最近更新 更多