【问题标题】:ASP.NET C# thread aborted exception?ASP.NET C# 线程中止异常?
【发布时间】:2011-05-27 04:13:24
【问题描述】:

我正在尝试构建一个小型电子邮件工作者来发送我的电子邮件。电子邮件工作者在自己的线程中运行。 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;
}

【问题讨论】:

    标签: c# asp.net multithreading global-asax threadabortexception


    【解决方案1】:

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

    【讨论】:

      【解决方案2】:

      您正在创建的线程正在被 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 封电子邮件,因此计时器滴答结束,新的邮件会升起...

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

      【讨论】:

      • 这就是为什么要将需要 24/7 全天候运行的东西从 ASP.NET 项目中移到 Windows 服务中的原因。
      【解决方案3】:

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

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

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

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

      【讨论】:

        【解决方案4】:

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

        【讨论】:

        • 这不是真的,你可以像他一样在应用程序中启动线程,并且它们不绑定到任何特定的请求线程。他的异常发生是因为他的代码告诉线程Abort()
        • @Coding Gorilla - 在哪里?我看到的唯一中止是在应用程序端。如果它没有绑定到请求线程,那么为什么最终的 Debug 在中止之前不会触发?我以前在 Asp.Net 中使用线程的其他用途也发生过这种情况,但我承认我从未尝试在应用程序级代码中放置线程声明。
        • 我相信最终的Debug.Write(e.Message) 确实会火。如果您查看他的例外情况:An exception of type 'System.Threading.ThreadAbortException' occurred in mscorlib.dll but was not handled in user code。这将是最后一条消息,如果您阅读 ThreadAbortException 上的 MSDN 文档,您永远无法完全抓住它,它总是会被重新抛出。
        【解决方案5】:

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

         EmailWorkerThread.Abort();
        

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

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

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2010-11-10
          • 2010-12-23
          • 2011-04-15
          • 2010-11-04
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多