简体   繁体   English

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

[英]ASP.NET C# thread aborted exception?

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. global.asax启动线程,然后运行一轮,然后抛出此异常。 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 mscorlib.dll中发生类型'System.Threading.ThreadAbortException'的第一次机会异常
An exception of type 'System.Threading.ThreadAbortException' occurred in mscorlib.dll but was not handled in user code mscorlib.dll中发生类型'System.Threading.ThreadAbortException'的异常,但未在用户代码中处理

This is the code for the EmailWorker 这是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: 这是启动所有内容的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;
}

You need to move the EmailWorker out of ASP.NET and into windows service. 您需要将EmailWorker移出ASP.NET并移到Windows服务中。 You can communicate between your webpage and the service via WCF. 您可以通过WCF在网页和服务之间进行通信。 ASP.NET is not meant for long running tasks. ASP.NET不适用于长时间运行的任务。

The ThreadAbortException occurs when your application shuts down and you call EmailWorkerThread.Abort() . 当您的应用程序关闭并调用EmailWorkerThread.Abort()时,将发生ThreadAbortException 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. 这是预期的行为,它发生在随机的位置,因为当Application_End在线程上调用Abort()时,代码可能位于不同的“位置”。

As per MSDN , the ThreadAbortException is a special exception that is always rethrown even after being handled by your code. 根据MSDNThreadAbortException是一个特殊的异常,即使在您的代码处理之后,该异常也总是被抛出。 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. 您的应用程序可能已关闭,因为IIS在设置了一定的空闲时间或某些其他限制后关闭了工作进程。 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. 同样,这是可以预期的,ASP.NET应用程序往往具有“有限的生存期”,因此,像这样长时间运行的线程并不是一个好主意。

I'm not sure what your exact question was, but hopefully I answered it. 我不确定您的确切问题是什么,但希望我能回答。

The thread that you are creating is being aborted by asp.net. 您正在创建的线程被asp.net中止。 Creating long running threads are a major no-no in asp.net. 在asp.net中,创建长时间运行的线程是一个主要的禁忌。

A we have a working workaround, that we are not proud of... Create a timer that process pending emails. A我们有一个可行的解决方法,我们不为此感到骄傲...创建一个计时器来处理未决的电子邮件。

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... 要特别小心,在Timer_Tick事件中,最多处理N封电子邮件,因此计时器滴答结束,并且新的滴答出现……

This is working on our production environment... 这正在我们的生产环境中进行...

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. 即使您在似乎是应用程序级别的位置上定义了一个线程,我也无法想象该线程实际上可以在HttpRequest线程之外生存。 To me this means that the moment your request thread terminates, your child EmailWorkerThread terminates. 对我来说,这意味着您的请求线程终止时,您的子级EmailWorkerThread终止。 Since the thread is sleeping, the next line attempts to execute but it can't because the HttpRequest thread has already run its course. 由于线程处于休眠状态,因此下一行尝试执行,但由于HttpRequest线程已经运行,因此无法执行。

ThreadAbortException as the name implies, is thrown when a thread is working and is aborted. ThreadAbortException顾名思义,当线程正在工作并且中止时抛出该异常。 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. 更好的实现是将无限循环替换为可取消循环。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM