短信平台记录日志模块,是通过异步方式来记录的,即日志工具类里初始化一个Queue对象,公共的写日志方法的处理逻辑是把日志消息放到Queue里。构造器里设定一个死循环,不停的读队,然后把日志消息持久化到磁盘的文本文件里。

构造方法的代码如下:

public Log()
{
//开启线程负责将日志写入到指定地点
ThreadPool.QueueUserWorkItem(o =>
{
try
{
while (true)
{
if (_messageQueue.Count > )
{
lock (_messageQueue)
{
while (_messageQueue.Count > )
{
LogMessage logMessage = _messageQueue.Dequeue();
WriteFile(logMessage);
}
}
}
else
{
Thread.Sleep();
}
}
}
catch (Exception ex)
{
LogMessage log = new LogMessage() { Content = "构造器执行报错:" + ex.ToString() };
FileHelper.WriteFile(string.Format(@"{0}\{1:yyyy-MM-dd}-LOGERROR.txt", _logPath, DateTime.Now), log.GetFormattedLog());
}
});
}

近期通过看线上站点日志,发现不定期会有ThreadAbortException被捕获,

时间:-- ::
构造器执行报错:System.Threading.ThreadAbortException: 正在中止线程。
在 System.Threading.Thread.SleepInternal(Int32 millisecondsTimeout)
在 Common.Log.<.ctor>b__1(Object o)
-------------------------------------------------------------------------------
时间:-- ::
构造器执行报错:System.Threading.ThreadAbortException: 正在中止线程。
在 System.Threading.Thread.SleepInternal(Int32 millisecondsTimeout)
在 Common.Log.<.ctor>b__2(Object o)
----------------------------------------------------------------------------------------

通过分析,当站点应用程序池回收或遇到其他未捕获的异常时,线程会被Abort,这时,当线程里的代码再被执行时,就会抛出ThreadAbortException异常。

微软官方对ThreadAbortException的介绍:

在调用 Abort 方法以销毁线程时,CLR将引发ThreadAbortExceptionThreadAbortException 是一种可捕获的特殊异常,但在 catch 块的结尾处它将自动被再次引发。引发此异常时,运行库将在结束线程前执行所有 finally 块。由于线程可以在 finally 块中执行未绑定计算,或调用 Thread.ResetAbort 来取消中止,所以不能保证线程将完全结束。如果您希望一直等到被中止的线程结束,可以调用 Thread.Join 方法。Join 是一个模块化调用,它直到线程实际停止执行时才返回。

下面的示例说明如何中止线程。接收 ThreadAbortException 的线程使用 ResetAbort 方法取消中止请求并继续执行。

using System;
using System.Threading;
using System.Security.Permissions; public class ThreadWork {
public static void DoWork() {
try {
for(int i=; i<; i++) {
Console.WriteLine("Thread - working.");
Thread.Sleep();
}
}
catch(ThreadAbortException e) {
Console.WriteLine("Thread - caught ThreadAbortException - resetting.");
Console.WriteLine("Exception message: {0}", e.Message);
Thread.ResetAbort();
}
Console.WriteLine("Thread - still alive and working.");
Thread.Sleep();
Console.WriteLine("Thread - finished working.");
}
} class ThreadAbortTest {
public static void Main() {
ThreadStart myThreadDelegate = new ThreadStart(ThreadWork.DoWork);
Thread myThread = new Thread(myThreadDelegate);
myThread.Start();
Thread.Sleep();
Console.WriteLine("Main - aborting my thread.");
myThread.Abort();
myThread.Join();
Console.WriteLine("Main ending.");
}
}

运行结果:

Thread - working.
Main - aborting my thread.
Thread - caught ThreadAbortException - resetting.
Exception message: Thread was being aborted.
Thread - still alive and working.
Thread - finished working.
Main ending.

————————————————————–我是萌萌哒分界线————————————————————

生产者/消费者模式
我们系统里的日志Helper类用到了Queue来实现异步记日志,提高系统容错和性能。现在想来,这就是一个生产者/消费者模式的运用。
在分布式系统中,这个模式更适用,尤其是消息处理。 RabbitMQ正是基于这种需求而产生的消息中间件。
 

Thread.Sleep引发ThreadAbortException异常的更多相关文章

  1. C# Thread.Abort方法与ThreadAbortException异常(取消线程与异常处理)

    1.Abort当前线程,后续程序不会执行 class Program { public static Thread thread1; static void Main(string[] args) { ...

  2. 选择目录,选择文件夹的COM组件问题。在可以调用 OLE 之前,必须将当前线程设置为单线程单元(STA)模式。请确保您的 Main 函数带有 STAThreadAttribute 标记。 只有将调试器附加到该进程才会引发此异常。

    异常: 在可以调用 OLE 之前,必须将当前线程设置为单线程单元(STA)模式.请确保您的 Main 函数带有 STAThreadAttribute 标记. 只有将调试器附加到该进程才会引发此异常. ...

  3. Response.End()出现ThreadAbortException 异常

    A. 如果使用 Response.End.Response.Redirect 或 Server.Transfer 方法,将出现 ThreadAbortException 异常.异常内容:由于代码已经过 ...

  4. c# Clipboard.SetDataObject(bmp1) 在可以调用 OLE 之前,必须将当前线程设置为单线程单元(STA)模式。请确保您的 Main 函数带有 STAThreadAttribute 标记。 只有将调试器附加到该进程才会引发此异常

    c# Clipboard.SetDataObject(bmp1)  在可以调用 OLE 之前,必须将当前线程设置为单线程单元(STA)模式.请确保您的 Main 函数带有 STAThreadAttri ...

  5. Response.End抛出ThreadAbortException 异常

    最近在写程序过程中遇到了一个匪夷所思的错误:Response.End()方法抛出了ThreadAbortException异常,我的代码如下: public void doResponse(){ st ...

  6. 将不确定变为确定~DateTime.MinValue和MaxValue引发的异常

    回到目录 问题描述: SqlDateTime 溢出.必须介于 1/1/1753 12:00:00 AM 和 12/31/9999 11:59:59 PM 之间 概念相关 .Net中的DateTime结 ...

  7. WPF控件ComboBox 每个Item的ToolTip引发的异常

    介绍 首先介绍下要实现的任务.做一个下拉框,当选择每个项的时候将鼠标发在上面显示该项的ToolTip的内容(Image). 实现 Model: public class SkinInfo : Noti ...

  8. VS2010 F5调试时出现:“ 尝试运行项目时出错:未捕获通过反射调用的方法引发的异常”解决

    VS2010 F5调试时出现 尝试运行项目时出错:未捕获通过反射调用的方法引发的异常 两个解决方法:1) 打开项目属性,选择调试选项卡,将“启用非托管代码调试”一项钩上.2) 打开项目属性,选择调试选 ...

  9. WPF关于“在“System.Windows.Markup.StaticResourceHolder”上提供值时引发了异常。”问题解决办法

    在WPF中添加样式,在MainWindow.xaml使用自定义按钮FButton时报错,报错信息如下: "System.Windows.Markup.XamlParseException&q ...

随机推荐

  1. Javascript-常用字符串数组操作

    字符串的操作在编写Js的过程中是不可避免的 因为它太多的API 还有相似的API让我们很头痛 为了避免以后遇到模拟两可的问题 还是做个笔记比较好 把常用的字符串操作记录下来成笔记 方便以后查找 No1 ...

  2. echarts之tooltip-showContent

    当trigger:为'axis'时 tooltip : { trigger: 'axis', showContent:false } 当trigger:为'item'时 tooltip : { tri ...

  3. fmt 标签格式化 日期

    <td class='center'> <fmt:formatDate value="${RecordMail.SendTime }" pattern=" ...

  4. 用Redis实现Session功能

    0.什么是Redis Redis是一个开源的使用ANSI C语言编写.支持网络.可基于内存亦可持久化的日志型.Key-Value数据库,并提供多种语言的API ---维基百科 1.与其他用户状态保存方 ...

  5. 从vue1.0到vue2.0遇到的一些问题的记录

    1.取消v-el的使用方式,改为refs使用 获取指定的dom元素 html:<div ref="div"></div> js: $refs.div 问题: ...

  6. js/jQuery使用过程中常见问题

    目录 一.jQuery选择器选择选中的或者disabled的选择框时attr函数无效 二.jQuery each函数的break/continue 三.jQuery 获取元素的left会值/left数 ...

  7. 【Python装饰者】在函数测试的作用

    [引言] 我们经常需要多函数进行耗时测试,测试方法有许多,这里介绍装饰者的方法,提高耗时测试代码的可复用性,在其他方面的应用也是如此. [设计原则] 类应该对扩展开放,对修改关闭. [代码] (1)定 ...

  8. mac osx Forbidden You don't have permission to access / on this server解决方法

    (1)首先查看*.conf 是否有读写权限,如果没有要将文件赋予读写权限,比如 localhost.conf (2)再查看/Users/username/Sites/localhost/文件夹是否有i ...

  9. WindowManager massge和handler

    在一个可移动浮动按钮的demo源码学习中,有一些WindowManager的使用,在此做下总结. 1.翻译过来就是窗口管理,是和应用框架层的窗口管理器交互的接口,通过 mWindowManager = ...

  10. MongoDB常用操作命令大全

    成功启动MongoDB后,再打开一个命令行窗口输入mongo,就可以进行数据库的一些操作.输入help可以看到基本操作命令,只是MongoDB没有创建数据库的命令,但有类似的命令 如:如果你想创建一个 ...