Ø  前言

本文主要记录子线程导致 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)的更多相关文章

  1. 因Window服务器自动更新并重启导致WebSphere服务停止服务故障一例

    最近公司购买了两台Windows Server 2008 R2服务器用于提供提供Web服务,A机器安装了IHS+DM+WAS8.5集群,B机器安装了Oracle11gR2用于数据存储,两台机器均可连接 ...

  2. 定时任务-C#线程类 windows服务

    原理 最常用的就是C#中 timer类写一个定时方法,然后在把他宿主到windows服务里面. C#中Timer分类 关于C# Timer类  在C#里关于定时器类就有3个 C# Timer使用的方法 ...

  3. 使用C#创建windows服务续之使用Topshelf优化Windows服务

    前言: 之前写了一篇“使用C#创建windows服务”,https://www.cnblogs.com/huangwei1992/p/9693167.html,然后有博友给我推荐了一个开源框架Tops ...

  4. 通过set和waitOne来控制子线程的运行和停止

    public partial class Form1 : Form { //自动重置事件类 //主要用到其两个方法 WaitOne() 和 Set() , 前者阻塞当前线程,后者通知阻塞线程继续往下执 ...

  5. 解决 docker 日志占满磁盘导致 docker 服务停止的问题

    #进入 root 模式 sudo -i # 查看目录大小 sudo du -h --max-depth=1 # 应该会定位到这个目录 `/var/libs/docker/containers` # 最 ...

  6. C# 开发的windows服务 不能调试——讨论整理

    CSDN的标题:C# 开发的windows服务 不能调试 System.Diagnostics.Debugger.Launch();在想加断点的地方加入这行,是进入断点的,可以进行调试,我的是xp系统 ...

  7. 如何查看子线程中的GC Alloc

    1)如何查看子线程中的GC Alloc2)Build时,提示安卓NDK异常3)如何获得ParticleSystem产生的三角形数量4)关于图片通道的问题5)GPUSkinning导致模型动画不平滑 M ...

  8. .NET Worker Service 作为 Windows 服务运行及优雅退出改进

    上一篇文章我们了解了如何为 Worker Service 添加 Serilog 日志记录,今天我接着介绍一下如何将 Worker Service 作为 Windows 服务运行. 我曾经在前面一篇文章 ...

  9. C#开发可以可视化操作的windows服务

    使用C#开发自定义windows服务是一件十分简单的事.那么什么时候,我们需要自己开发windows服务呢,就是当我们需要计算机定期或者一 直执行我们开发的某些程序的时候.我经常看到许多人开发的win ...

随机推荐

  1. js 时间类函数

    js 时间类是  Date() var currtime = new Date();// 实例一个时间,是当前时间 接收一个时间戳为参数 var time2=new Date(currtime.get ...

  2. Python里的赋值 拷贝 深拷贝

    import copy a = [1, 2, 3, 4, ['a', 'b']] #原始对象 b = a #赋值,传对象的引用 c = copy.copy(a) #对象拷贝,浅拷贝 d = copy. ...

  3. bzoj3756pty的字符串(后缀自动机+计数)

    题目描述 题解 我们可以先对trie树建出广义SAM,然后维护一下right集合大小(注意right集合在广义SAM上的维护方式). 然后把匹配穿往广义SAM上匹配,假设现在匹配到了x节点,那么x的所 ...

  4. docker命令篇

    基础命令: 镜像: 获取镜像 $ docker pull centos:7 下拉自己仓库镜像,在后面仓库部分会讲到. 列出镜像: $ docker image ls 删除镜像: $ docker im ...

  5. 20165223 实验四 Android开发基础

    实验四 Android开发基础 目录 一.实验报告封面 二.具体实验内容 (一)Android Stuidio的安装测试 (二)Activity测试 (三)UI测试 (四)布局测试 (五)教材代码测试 ...

  6. ACM-ICPC 2018 南京赛区网络预赛 J题Sum(线性筛素数)

    题目链接:https://nanti.jisuanke.com/t/30999 参考自博客:https://kuangbin.github.io/2018/09/01/2018-ACM-ICPC-Na ...

  7. Golang Kernel For Jupyter-NoteBook

    上篇回顾:VSCode and NoteBook for JavaScript 正常流程 安装Go语言:sudo apt install golang 安装内核的相关依赖包:sudo apt inst ...

  8. HDU/HDOJ 4864 Task

    贪心题. 贪心方法很是naive...... 首先我们就能注意到一个性质:优先选择时间(x)长的,然后才是等级(y). 所以我们把机器和任务排好序,从大到小枚举任务.对于每一个x满足的机器,x也一定满 ...

  9. java基本数据类型转换溢出问题

    java的基本数据类型有(int.byte.double.float.char.boolean.long.short):这里介绍整型数据 示例1: public class H_Z01 { publi ...

  10. 第三节,使用OpenCV 3处理图像(模糊滤波、边缘检测)

    一 不同色彩空间的转换 OpenCV中有数百种关于在不同色彩空间之间转换的方法.当前,在计算机中有三种常用的色彩空间:灰度,BGR以及HSV(Hue,Saturation,Value). 灰度色彩空间 ...