子线程导致 Windows 服务停止的情况(Topshelf 结合 Quartz.NET)
Ø 前言
本文主要记录子线程导致 Topshelf 和 Quartz.NET 的 Windows 服务停止的现象,以及使用几种常用子线程的注意事项。因为我们有时可能需要开启多个线程执行复杂的逻辑,如果某个子线发生了异常就导致服务停止了,那还怎么愉快的玩耍?!
1. 还是以之前使用 Quartz.NET 实现作业串行执行为例,我们模拟在“发送短信”和“发送邮件”中发生异常的情况,代码如下:
1) 首先修改 SendSMSJob 作业
/// <summary>
/// 发送短信作业。
/// </summary>
public class SendSMSJob : IJob
{
/// <summary>
/// 作业被触发时执行该方法。
/// </summary>
public void Execute(IJobExecutionContext context)
{
Log.Logger.InfoFormat("开始执行发送短信作业,线程Id为:{0}", Thread.CurrentThread.ManagedThreadId);
int i = 10, j = 0;
int r = i / j;
Log.Logger.InfoFormat("计算结果:{0} / {1} = {2}", i, j, r);
Log.Logger.Info("发送短信作业执行结束");
}
}
2) 然后再修改 SendMailJob 作业
/// <summary>
/// 发送邮件作业。
/// </summary>
public class SendMailJob : IJob
{
/// <summary>
/// 异步方法。
/// </summary>
public async void AsyncMethod1()
{
await Task.Run(() =>
{
try
{
Log.Logger.InfoFormat("开始执行(异步方法),线程为:{0}", Thread.CurrentThread.ManagedThreadId); ;
string str = ((object)null).GetType().Name;
Log.Logger.InfoFormat("结束执行(异步方法),结果:{0}", str);
}
catch (Exception ex)
{
Log.Logger.ErrorFormat("发送邮件作业发生异常:{0}", ex.Message);
}
});
}
/// <summary>
/// 作业被触发时执行该方法。
/// </summary>
public void Execute(IJobExecutionContext context)
{
Log.Logger.InfoFormat("开始执行发送邮件作业,线程Id为:{0}", Thread.CurrentThread.ManagedThreadId);
//1. 使用委托异步调用的线程
Action action = new Action(() =>
{
try
{
Log.Logger.InfoFormat("开始执行(委托异步),线程为:{0}", Thread.CurrentThread.ManagedThreadId); ;
string str = ((object)null).GetType().Name;
Log.Logger.InfoFormat("结束执行(委托异步),结果:{0}", str);
}
catch (Exception ex)
{
Log.Logger.ErrorFormat("发送邮件作业发生异常:{0}", ex.Message);
}
});
action.BeginInvoke((asyncResult) =>
{
Action aciton = asyncResult.AsyncState as Action;
aciton.EndInvoke(asyncResult);
}, action);
//2. 使用开启的新线程
Thread thread = new Thread(() =>
{
try
{
Log.Logger.InfoFormat("开始执行(开启新线程),线程为:{0}", Thread.CurrentThread.ManagedThreadId); ;
string str = ((object)null).GetType().Name;
Log.Logger.InfoFormat("结束执行(开启新线程),结果:{0}", str);
}
catch (Exception ex)
{
Log.Logger.ErrorFormat("发送邮件作业发生异常:{0}", ex.Message);
}
});
thread.Start();
//3. 使用线程池中的线程
System.Threading.ThreadPool.QueueUserWorkItem((state) =>
{
try
{
Log.Logger.InfoFormat("开始执行(线程池),线程为:{0}", Thread.CurrentThread.ManagedThreadId); ;
string str = ((object)null).GetType().Name;
Log.Logger.InfoFormat("结束执行(线程池),结果:{0}", str);
}
catch (Exception ex)
{
Log.Logger.ErrorFormat("发送邮件作业发生异常:{0}", ex.Message);
}
});
//4. 使用异步方法中的线程(以 System.Threading.Tasks.Task.Run() 方式)
AsyncMethod1();
//5. 使用异步任务中的线程(以 System.Threading.Tasks.Task.Run() 方式)
System.Threading.Tasks.Task.Run(() =>
{
Log.Logger.InfoFormat("开始执行(Task.Run()),线程为:{0}", Thread.CurrentThread.ManagedThreadId); ;
string str = ((object)null).GetType().Name;
Log.Logger.InfoFormat("结束执行(Task.Run()),结果:{0}", str);
});
//6. 使用异步任务中的线程(以 System.Threading.Tasks.Task.Factory.StartNew() 方式)
System.Threading.Tasks.Task.Factory.StartNew(() =>
{
Log.Logger.InfoFormat("开始执行(Task.Factory.StartNew()),线程为:{0}", Thread.CurrentThread.ManagedThreadId); ;
string str = ((object)null).GetType().Name;
Log.Logger.InfoFormat("结束执行(Task.Factory.StartNew()),结果:{0}", str);
}).Start();
Log.Logger.Info("发送邮件作业执行结束");
}
}
2. 分别运行 SendMailJob 作业的几种方式(运行时注释其他 5 种方式)
1) 没有加 try/catch 的情况


2) 加了 try/catch 的情况

3) 分析与总结
1. 首先主线程(就是 windows 服务主动开启的线程)发生异常时,终止当前线程执行,但不会停止服务。
2. 【推荐】异步任务(Task)开启的线程发生异常时,也是终止当前线程执行,但不会停止服务。
3. 使用(未加 try/catch 时)委托异步调用的线程、开启的新线程、线程池中的线程、异步方法中的线程,发生异常时,会停止服务!
4. 使用(加 try/catch 时)开启的新线程、线程池中的线程、异步方法中的线程,发生异常时,不会停止服务。
5. 使用(加 try/catch 时)委托异步调用的线程同样会停止服务!
子线程导致 Windows 服务停止的情况(Topshelf 结合 Quartz.NET)的更多相关文章
- 因Window服务器自动更新并重启导致WebSphere服务停止服务故障一例
最近公司购买了两台Windows Server 2008 R2服务器用于提供提供Web服务,A机器安装了IHS+DM+WAS8.5集群,B机器安装了Oracle11gR2用于数据存储,两台机器均可连接 ...
- 定时任务-C#线程类 windows服务
原理 最常用的就是C#中 timer类写一个定时方法,然后在把他宿主到windows服务里面. C#中Timer分类 关于C# Timer类 在C#里关于定时器类就有3个 C# Timer使用的方法 ...
- 使用C#创建windows服务续之使用Topshelf优化Windows服务
前言: 之前写了一篇“使用C#创建windows服务”,https://www.cnblogs.com/huangwei1992/p/9693167.html,然后有博友给我推荐了一个开源框架Tops ...
- 通过set和waitOne来控制子线程的运行和停止
public partial class Form1 : Form { //自动重置事件类 //主要用到其两个方法 WaitOne() 和 Set() , 前者阻塞当前线程,后者通知阻塞线程继续往下执 ...
- 解决 docker 日志占满磁盘导致 docker 服务停止的问题
#进入 root 模式 sudo -i # 查看目录大小 sudo du -h --max-depth=1 # 应该会定位到这个目录 `/var/libs/docker/containers` # 最 ...
- C# 开发的windows服务 不能调试——讨论整理
CSDN的标题:C# 开发的windows服务 不能调试 System.Diagnostics.Debugger.Launch();在想加断点的地方加入这行,是进入断点的,可以进行调试,我的是xp系统 ...
- 如何查看子线程中的GC Alloc
1)如何查看子线程中的GC Alloc2)Build时,提示安卓NDK异常3)如何获得ParticleSystem产生的三角形数量4)关于图片通道的问题5)GPUSkinning导致模型动画不平滑 M ...
- .NET Worker Service 作为 Windows 服务运行及优雅退出改进
上一篇文章我们了解了如何为 Worker Service 添加 Serilog 日志记录,今天我接着介绍一下如何将 Worker Service 作为 Windows 服务运行. 我曾经在前面一篇文章 ...
- C#开发可以可视化操作的windows服务
使用C#开发自定义windows服务是一件十分简单的事.那么什么时候,我们需要自己开发windows服务呢,就是当我们需要计算机定期或者一 直执行我们开发的某些程序的时候.我经常看到许多人开发的win ...
随机推荐
- Dynamic CRM 2015学习笔记(3)oData 查询方法及GUID值比较
本文将比较二种查询字符串在同一个oData查询方法中的不同,另外,还将介绍如何比较不同方法返回的GUID的值. 用同一个oData查询方法,如果传入查询的字符串不一样,返回结果的格式竟然完全不一样. ...
- 【php】 php获取文件路径中的文件名和文件后缀方法
获取文件名 $file = realpath(__DIR__.'/images/common/../addBtn.png'); 方法一 $file = realpath(__DIR__.'/image ...
- angularjs优化方略
angular优化方略,闲的没事想重构的人来瞅瞅. 1.减少$watch 减少$watch,减少$watch,减少$watch.不仅仅是$watch监听,还有ng-model,别闲的没事就加个ng-m ...
- Go 语言和 Scala 语言对比
我在Google写过Go(自己的业余时间),也在LinkedIn写过Scala.两者都是具有一流的并发特性的现代语言. 下面的回答是基于我编写大规模的软件的经验得出. Go是一种开发模式严格固定,并且 ...
- css 多行文本的溢出显示省略号(移动端)
多行文本的溢出显示省略号(移动端) 一.单行文本的溢出显示省略号(通用) .mui-ellipsis { overflow: hidden; /*规定当文本溢出包含元素时发生的事情*/ white-s ...
- Docker普通用户不使用sudo提权
解决方法 sudo groupadd docker 添加Docker用户组 sudo gpasswd -a ${USER} docker 添加你的用户到Docker用户组 reboot 重启系统.也可 ...
- Git中撤销提交
Git的几种状态 未修改 原始内容 已修改 ↓ 工 作 区 已暂存 ↓ git add 暂 存 区 已提交 ↓ git commit 本地仓库 已推送 ↓ git push 远程仓库 注意:下面所有命 ...
- java面试——问题回溯
背景:用来记录面试过程中遇到的问题,在这里进行记录,下次不要犯同样的错误. 迪普科技 Linux服务器下的top命令 #动态更新的虚拟文件实际上是许多其他内存相关工具(如:free / ps / to ...
- JavaScript(JS)之Javascript对象BOM,History,Location,Function...(二)
https://www.cnblogs.com/haiyan123/p/7594046.html 在JavaScript中除了null和undefined以外其他的数据类型都被定义成了对象,也可以用创 ...
- 新建工程时报错(26, 13) Failed to resolve: com.android.support:appcompat-v7:28.+ ,
allprojects { repositories { jcenter() maven { url "https://maven.google.com" } } }