2

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

这是抛出的异常:

在电子邮件工作者 for-loop 中开始新一轮 在电子邮件工作者 for-loop
中进入睡眠 在
mscorlib.dll 中发生“System.Threading.ThreadAbortException”类型的第一次机会异常“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;
}
4

5 回答 5

3

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

于 2011-03-15T22:06:42.783 回答
1

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

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

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

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

于 2010-12-17T14:59:32.703 回答
1

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

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)

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

这正在我们的生产环境中工作......

于 2010-12-17T15:05:07.277 回答
0

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

于 2010-12-17T14:54:40.323 回答
0

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

 EmailWorkerThread.Abort();

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

更好的实现是用可取消循环替换无限循环。

于 2010-12-17T14:58:15.290 回答