今天,发现我们的一个Windows Service无法正常停止,无奈之下只能杀了进程。

为了找到原因,我在本地进行调试,发现程序里用到了多线程,而代码正是卡在了workThread.Abort()语句而无法停止。

为什么不能Abort? 继续看线程调用的方法的代码,发现没有什么特殊的代码,只是在其中用了Thread.Sleep进行长时间等待。

难道是这个引起的? 写了一个测试程序验证,

class Program
{
private readonly Thread workThread; public Program()
{
workThread = new Thread(DoWork);
} static void Main(string[] args)
{
new Program().Work();
Console.ReadLine();
} private void Work()
{
workThread.Start();
Thread.Sleep(1 * 1000); Console.WriteLine("aborting");
workThread.Abort();
Console.WriteLine("aborted");
} private void DoWork()
{
Console.WriteLine("started");
Thread.Sleep(300 * 1000);
}
}

发现可以正常终止。

started
aborting
aborted

再仔细检查,发现其中一处Thread.Sleep放在了finally块中,修改测试代码

class Program
{
private readonly Thread workThread; public Program()
{
workThread = new Thread(DoWork);
} static void Main(string[] args)
{
new Program().Work();
Console.ReadLine();
} private void Work()
{
workThread.Start();
Thread.Sleep( * );
Console.WriteLine("aborting");
workThread.Abort(); Console.WriteLine("aborted");
} private void DoWork()
{
try
{
Console.WriteLine("started");
}
catch (Exception)
{
throw;
}
finally
{
for (int i = ; i < ; i++)
{
Console.WriteLine("ThreadState:" + workThread.ThreadState);
Thread.Sleep();
}
}
}
}

输出:

started
ThreadState:Running
aborting
ThreadState:AbortRequested
ThreadState:AbortRequested
aborted

MSDN是这样解释的:

线程不一定会立即中止,或者根本不中止。 如果线程在作为中止过程的一部分被调用的 finally 块中做非常大量的计算,从而无限期延迟中止操作,则会发生这种情况。

http://msdn.microsoft.com/zh-cn/library/5b50fdsz.aspx

其实追根溯源,问题是出在程序员对try-catch-finally的滥用上,finally块应该是用来做一些收尾工作,而不是等待操作。

finally 块用于清除 try 块中分配的任何资源,以及运行任何即使在发生异常时也必须执行的代码。

http://msdn.microsoft.com/zh-cn/library/zwc8s4fz%28v=vs.80%29.aspx

找到了原因,解决方案也挺简单,将Thread.Sleep从finally块中移除即可。

try-catch-finally 引发的奇怪问题的更多相关文章

  1. 移动页面click延迟引发的touch问题

    一.事件捕获与冒泡 先扯一下事件的触发流程,这个之后会用到. DOM2级事件规定事件包括三个阶段: ① 事件捕获阶段 ② 处于目标阶段 ③ 事件冒泡阶段 大概的流程就是事件从最外层一层一层往里面传递( ...

  2. [转] C++ try catch() throw 异常处理

    原文地址 其它很多程序员一样,本书的主人公阿愚也是在初学C++时,在C++的sample代码中与异常处理的编程方法初次邂逅的,如下:   // Normal program statements  . ...

  3. 异常处理(try catch throw)详解(C++)

    选择异常处理的编程方法的具体原因如下: 1.把错误处理和真正的工作分开来: 2.代码更易组织,更清晰,复杂的工作任务更容易实现: 3.毫无疑问,更安全了,不至于由于一些小的疏忽而使程序意外崩溃了: 4 ...

  4. 小型单文件NoSQL数据库SharpFileDB初步实现

    小型单文件NoSQL数据库SharpFileDB初步实现 我不是数据库方面的专家,不过还是想做一个小型的数据库,算是一种通过mission impossible进行学习锻炼的方式.我知道这是自不量力, ...

  5. 12、uwp 开发的零碎总结

    1.在给位 “修正版本号”(Major.Minor.Build.Revision)不能修改. 后, 商店上传失败,描述信息为:Apps are not allowed to have a Versio ...

  6. 了解CAdoSqlserver

    include <vector> 表示引用了vector类, vector是STL中的一种数据结构,或者叫容器,功能相当于数组,但是功能强大很多.vector在C++标准模板库中的部分内容 ...

  7. #pragma once与#ifndef #define ...#endif的区别

    1. #pragma once用来防止某个头文件被多次include: #ifndef,#define,#endif用来防止某个宏被多次定义.   2. #pragma once是编译相关,就是说这个 ...

  8. Oracle软件安装目录满的清理方法

    这是Oracle数据库日常运维中很常见的一个场景,安装目录满有时不光会导致无法记录最新数据库的日志信息,导致遇到问题无法查到最新的日志信息,还会引发一些奇怪的问题. 所以日常巡检要保证Oracle的安 ...

  9. #pragma once与 #ifndef的区别

      为了避免同一个文件被include多次 1   #ifndef方式2   #pragma once方式 在能够支持这两种方式的编译器上,二者并没有太大的区别,但是两者仍然还是有一些细微的区别.   ...

随机推荐

  1. Kindle DXG和Win10 64bits无法连接的问题

    直入主题:换根数据线. 不要觉得答案简单,我就是不负责任的在调侃. 在得出这条答案之前,我的思路是,既然插上线以后,kindle的充电指示灯会亮,那就应该不是线的问题. 所以实际的过程是我安装了驱动之 ...

  2. 百度网盘kbengine - warring项目下载地址

    http://pan.baidu.com/s/1k4J4y 下载解压之后,请看<<使用说明.doc>>,有更新指导

  3. easycwmp的交叉编译

    原创作品,转载请注明出处 copyright:weishusheng   2015.3.18 email:642613208@qq.com 平台: Linux version 2.6.32-279.e ...

  4. 总是弹出visual studio 实时调试器 三种解决办法

    最近服务器老是弹出visual studio 实时调试器很是郁闷呀.关还关不掉.怎么解决呢 ,现像如下图所示: 下面我们一起来分析一下这种情况的原因: 弹出应用程序: Visual Studio 实时 ...

  5. Eclipse启动tomcat时出现报错-拒绝访问

    今天新建项目,当选择项目的发布路径为tomcat的路径时 启动tomcat出现如下错误: Publishing the configuration... Error copying file to D ...

  6. [转]权限问题导致Nginx 403 Forbidden错误的解决方法

    权限问题导致Nginx 403 Forbidden错误的解决方法 投稿:junjie 字体:[增加 减小] 类型:转载 时间:2014-08-22 这篇文章主要介绍了权限问题导致Nginx 403 F ...

  7. putty+xming远程登录Ubuntu16.04图形界面

    前面我写过一篇<Ubuntu16.04 安装ftp服务器传输文件>的文章.文章当中已经可以远程访问linux服务器并且传输文件,然而要在putty中使用开启图形界面的命令到目前为止还是不够 ...

  8. securityCRT mongoDB 命令行删除(backspace/delete)无效问题

    1.MongoDB Shell中退格键使用的问题. 利用SecureCRT工具访问linux的时候,在使用MongoDB的交互式shell的时候,退格键(Backspace)无法使用,导致无法修改输入 ...

  9. HackerRank "Equal Stacks"

    Greedy - though simple, but fun! #include <vector> #include <iostream> using namespace s ...

  10. 常用Java排序算法

    常用Java排序算法 冒泡排序 .选择排序.快速排序 package com.javaee.corejava; public class DataSort { public DataSort() { ...