ASP.NET C# 线程中止异常?

发布于 10-08 03:02 字数 2637 浏览 7 评论 0原文

我正在尝试构建一个小型电子邮件工作者来发送我的电子邮件。电子邮件工作人员在其自己的线程中运行。 global.asax 启动线程,然后在抛出此异常之前运行一轮。我一直试图找出它把它扔到哪里,但似乎每次都不一样。记录被打印到文本文件中以便可以工作,也许是处置功能?

这是抛出的异常:

在电子邮件中开始新一轮 工人for循环
要去睡觉了 电子邮件工作者 for 循环
第一次机会 类型异常 'System.Threading.ThreadAbortException' 发生在 mscorlib.dll
一个例外 类型的 'System.Threading.ThreadAbortException' 发生在 mscorlib.dll 中但不是 在用户代码中处理

这是 EmailWorker 的代码

public static class EmailWorker
{
    public static void Work()
    {
        TimeSpan sleepTime = new TimeSpan(0, 1, 0);

        for (; ; )
        {
            Debug.WriteLine("Starting a new round in the email worker for-loop");
            try
            {
                // Get the records
                CS_Code.UtopiaDataContext db = new CS_Code.UtopiaDataContext(); 
                List<CS_Code.Global_Email> emailsToSend = (from xx in db.Global_Emails select xx).ToList();


                // Write the records to a file (for now)
                TextWriter writer = new StreamWriter(@"test.txt", true); // For debugging
                foreach (var email in emailsToSend)
                    writer.WriteLine("To: " + email.Email_Address + ", Subject: " + email.Subject + ", uid:" + email.UserName.ToString());
                writer.Close();
                writer.Dispose();

                // Delete the used records from the database
                foreach (var email in emailsToSend)
                    db.Global_Emails.DeleteOnSubmit(email);
                db.SubmitChanges();
                db.Dispose();


                Debug.WriteLine("Going to sleep in the email worker for-loop");
                Thread.Sleep(sleepTime); // Sleep for 1 minute.
                Debug.WriteLine("Just woke up in the email worker for-loop");
            }
            catch (Exception e)
            {               
                Debug.WriteLine(e.Message);
                break;
            }
        }
    }
}

这是启动一切的 global.asax 文件:

private static Thread EmailWorkerThread { get; set; }

void Application_Start(object sender, EventArgs e)
{
    // Email worker thread
    if ((EmailWorkerThread == null) || (!EmailWorkerThread.IsAlive))
    {
        ThreadStart ts = new ThreadStart(EmailWorker.Work);
        EmailWorkerThread = new Thread(ts);
        EmailWorkerThread.Start();
    }
}

void Application_End(object sender, EventArgs e)
{
    // Email worker thread
    if ((EmailWorkerThread != null) || (EmailWorkerThread.IsAlive))
        EmailWorkerThread.Abort();
    EmailWorkerThread = null;
}

i am trying to build a small email worker that sends my emails. The email worker operates in its own thread. The global.asax starts the thread and then it runs for one round before throwing this exception. I have been trying to find out where it throws it, but it seems to be different each time. The records are printed to the text file so that works, maybe the dispose functions?

This is the exception thrown:

Starting a new round in the email
worker for-loop
Going to sleep in the
email worker for-loop
A first chance
exception of type
'System.Threading.ThreadAbortException'
occurred in mscorlib.dll
An exception
of type
'System.Threading.ThreadAbortException'
occurred in mscorlib.dll but was not
handled in user code

This is the code for the EmailWorker

public static class EmailWorker
{
    public static void Work()
    {
        TimeSpan sleepTime = new TimeSpan(0, 1, 0);

        for (; ; )
        {
            Debug.WriteLine("Starting a new round in the email worker for-loop");
            try
            {
                // Get the records
                CS_Code.UtopiaDataContext db = new CS_Code.UtopiaDataContext(); 
                List<CS_Code.Global_Email> emailsToSend = (from xx in db.Global_Emails select xx).ToList();


                // Write the records to a file (for now)
                TextWriter writer = new StreamWriter(@"test.txt", true); // For debugging
                foreach (var email in emailsToSend)
                    writer.WriteLine("To: " + email.Email_Address + ", Subject: " + email.Subject + ", uid:" + email.UserName.ToString());
                writer.Close();
                writer.Dispose();

                // Delete the used records from the database
                foreach (var email in emailsToSend)
                    db.Global_Emails.DeleteOnSubmit(email);
                db.SubmitChanges();
                db.Dispose();


                Debug.WriteLine("Going to sleep in the email worker for-loop");
                Thread.Sleep(sleepTime); // Sleep for 1 minute.
                Debug.WriteLine("Just woke up in the email worker for-loop");
            }
            catch (Exception e)
            {               
                Debug.WriteLine(e.Message);
                break;
            }
        }
    }
}

This is the global.asax file that starts everything:

private static Thread EmailWorkerThread { get; set; }

void Application_Start(object sender, EventArgs e)
{
    // Email worker thread
    if ((EmailWorkerThread == null) || (!EmailWorkerThread.IsAlive))
    {
        ThreadStart ts = new ThreadStart(EmailWorker.Work);
        EmailWorkerThread = new Thread(ts);
        EmailWorkerThread.Start();
    }
}

void Application_End(object sender, EventArgs e)
{
    // Email worker thread
    if ((EmailWorkerThread != null) || (EmailWorkerThread.IsAlive))
        EmailWorkerThread.Abort();
    EmailWorkerThread = null;
}

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

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

发布评论

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

评论(5

沧笙踏歌2024-10-15 03:02:34

您需要将 EmailWorker 从 ASP.NET 移出并移至 Windows 服务中。您可以通过 WCF 在网页和服务之间进行通信。 ASP.NET 不适合长时间运行的任务。

You need to move the EmailWorker out of ASP.NET and into windows service. You can communicate between your webpage and the service via WCF. ASP.NET is not meant for long running tasks.

像你2024-10-15 03:02:34

您正在创建的线程正被 asp.net 中止。创建长时间运行的线程是 ASP.NET 中的一大禁忌。

我们有一个可行的解决方法,但我们并不为此感到自豪...创建一个处理待处理电子邮件的计时器。

static Timer processTimer; // declare static at service level

// At the static constructor:
processTimer = new Timer(new TimerCallback(TimerTick), 60000, 10000, defaultInterval); //wait a minute before begin (dueTime = 60000)

要格外小心,在 Timer_Tick 事件中,最多处理 N 封电子邮件,因此计时器滴答结束,新的一封邮件升起...

这在我们的生产环境中起作用...

The thread that you are creating is being aborted by asp.net. Creating long running threads are a major no-no in asp.net.

A we have a working workaround, that we are not proud of... Create a timer that process pending emails.

static Timer processTimer; // declare static at service level

// At the static constructor:
processTimer = new Timer(new TimerCallback(TimerTick), 60000, 10000, defaultInterval); //wait a minute before begin (dueTime = 60000)

To be extra carefull, at the Timer_Tick event, handle at most N emails, so the timer tick ends, and a new one rises...

This is working on our production environment...

橘香2024-10-15 03:02:34

当您的应用程序关闭并且您调用 EmailWorkerThread.Abort() 时,会发生 ThreadAbortException。这是预期的行为,它会在随机位置发生,因为当 Application_End 在线程上调用 Abort() 时,代码可能位于不同的“点”。

根据 MSDNThreadAbortException 是一个特殊的异常,即使在代码处理之后也总是会重新抛出。它的目的是让您知道线程正在关闭,以便您有机会进行清理。

您的应用程序可能会关闭,因为 IIS 在经过设定的空闲时间或其他一些强加的限制后关闭工作进程。同样,这是可以预料的,ASP.NET 应用程序往往具有“有限的生命周期”,因此像这样长时间运行的线程并不是一个好主意。

我不确定你的具体问题是什么,但希望我能回答。

The ThreadAbortException occurs when your application shuts down and you call EmailWorkerThread.Abort(). This is expected behavior and it occurs in random places because the code can be in different "spots" when the Application_End calls Abort() on the thread.

As per MSDN, the ThreadAbortException is a special exception that is always rethrown even after being handled by your code. It's intended to let you know that the thread is shutting down to give you an opportunity to clean up.

You application is likely shutting down because IIS is shutting down the worker process after a set amount of idle time, or some other imposed limitation. Again, this is to be expected, ASP.NET applications tend to have "limited lifetimes", so long running threads like this are not really a good idea.

I'm not sure what your exact question was, but hopefully I answered it.

晚雾2024-10-15 03:02:34

只要父线程还活着,子线程就只能存活。即使您已经在应用程序级别定义了一个线程,但我无法想象该线程实际上在 HttpRequest 线程之外存在。对我来说,这意味着当您的请求线程终止时,您的子 EmailWorkerThread 也会终止。由于线程正在休眠,下一行尝试执行,但它不能执行,因为 HttpRequest 线程已经运行完毕。

The child thread can only live as long as the parent thread is alive. Even though you've got a thread defined in what appears to be the application level, I can't imagine this thread actually survives outside of the HttpRequest thread. To me this means that the moment your request thread terminates, your child EmailWorkerThread terminates. Since the thread is sleeping, the next line attempts to execute but it can't because the HttpRequest thread has already run its course.

烟花肆意2024-10-15 03:02:34

ThreadAbortException 顾名思义,当线程正在工作并被中止时抛出。这种情况发生在这个地方:

 EmailWorkerThread.Abort();

它无法被捕获,并且在应用程序结束时发生。

更好的实现是将无限循环替换为 cancelable 循环。

ThreadAbortException as the name implies, is thrown when a thread is working and is aborted. This happens at this place:

 EmailWorkerThread.Abort();

It cannot be caught and it happens when you application ends.

A better implementation would be to replace the infinite loop with cancelable loop.

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