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

发布于 2024-12-08 20:52:33 字数 1444 浏览 1 评论 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");
        }

    }
}

I've heard its bad to use ThreadPool in asp.net, however I've used it for the purpose of educating myself. My goal was to determine if the Application_Error event got fired (which is handled in the Global.asax) - my answer to that is: no, it does not get triggered.

But I had observed something strange. The thread I wrote simply queued up tasks to the threadpool. The task was meant to throw errors randomly. But I observed however that I keep frequently getting the error - the number exceeds the no. of times I've queued the task. A separate concern I have is even the System.Diagnostics.Trace.WriteLine() isn't logging messages to my output window (visual studio). Why this strange behaviour?

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");
        }

    }
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

红衣飘飘貌似仙 2024-12-15 20:52:33

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

不过,更大的问题是 generator.Next(1)总是返回 0。Random.Next(int max) 生成一个随机数数字 N,使得 0 <= N 最大。因此,您的 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 现在具有类范围,并且仅初始化一次。 的作用是防止多个线程尝试同时生成一个数字。如果没有锁,随机数生成器可能会被损坏,并且每次调用都会开始返回 0。我将 generator.Next 参数更改为 2,这样就可以获得数字 0 和 1。

There are two problems with your ErrorTask. The first is that you're initializing a new Random instance every time the method is called. The default Random constructor seeds the random number generator with the value from Environment.TickCount, which will likely be the same for consecutive threads. So you'll get the same random sequence for multiple threads.

The bigger problem, though, is that generator.Next(1) will always return 0. Random.Next(int max) generates a random number, N, such that 0 <= N < max. So your ErrorTask will throw the exception for every thread.

I have no idea how or why it would be throwing that exception more than once per call to ErrorTask. That doesn't seem possible.

I would suggest the following modification:

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 now has class scope and is initialized only once. The lock is there to prevent multiple threads from trying to generate a number at the same time. Without the lock, the random number generator can get corrupted and it will start returning 0 on every call. And I changed the parameter to generator.Next to 2, so you can get numbers 0 and 1.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文