System.Threading.Tasks.Task 任务引起的IIS应用程序池崩溃

转载:http://www.cnblogs.com/aaa6818162/p/4421305.html

问题现象

IIS应用程序池崩溃(Crash)的特征如下:

1. 从客户端看,浏览器一直处于连接状态,Web服务器无响应。

2. 从服务器端看(Windows Server 2008 + IIS 7.0),在事件日志中会出现Event ID为5010的错误:

A process serving application pool 'q.cnblogs.com' failed to respond to a ping. The process id was '20080'.

这个错误的意思是:IIS检测到程序池'q.cnblogs.com'无响应。为什么没有响应呢?因为程序池'q.cnblogs.com'崩溃了。然后呢?IIS会强制回收应用程序池。

(注:如果在你的Web服务器的事件日志中出现这个错误,一定是某个原因引起了应用程序池崩溃。)

问题原因

我们这次遇到的应用程序池崩溃,是由于在使用System.Threading.Tasks.Task进行异步操作时产生了未处理的异常。

示例代码如下:

Task.Factory.StartNew(() =>{    //下面的代码未用try..catch捕获异常    //...});

注:这是一个不需要Callback的异步操作,后续没有task.wait(或者静态方法Task.WaitAll或Task.WaitAny)操作。

当时我们发布程序后,由于Task中代码产生了异常,整个站点无法正常访问,程序池一直处于“崩溃->回收->崩溃->回收”的循环。

解决方法

捕获Task中所有代码的异常,示例代码如下:

Task.Factory.StartNew(() =>{    try    {        //... }    catch { }});

问题分析

在stackoverflow上提到了这个问题的原因

If you create a Task, and you don't ever call task.Wait() or try to retrieve the result of a Task<T>, when the task is collected by the garbage collector, it will tear down your application during finalization. For details, see MSDN's page on Exception Handling in the TPL.

The best option here is to "handle" the exception. 

根据上面的英文,我的理解是:当你创建一个Task,没有调用过task.Wait()或者没有获取它的执行结果,(如果Task中出现了未处理的异常),当这个Task被GC回收时,在GC finalization阶段,会让当前应用程序崩溃。

进一步看MSDN中的Exception Handling (Task Parallel Library)

"Unhandled exceptions that are thrown by user code that is running inside a task are propagated back to the joining thread. ···Exceptions are propagated when you use one of the static or instance Task.Wait or Task(Of TResult).Wait methods···"

翻译:在一个task中运行的代码抛出的未处理异常会被回传给(创建该task的)主线程。···当你调用Task.Wait时,异常才会被回传(给主线程)。

分析:当我们遇到的情况是没调用Task.Wait,也就是异常没有被回传给主线程。下面的这句就提到了这个:

"If you do not wait on a task that propagates an exception, or access its Exception property, the exception is escalated according to the .NET exception policy when the task is garbage-collected."

译:如果你在一个task中没有等待异常被传播,或者访问它的异步特性,在task被GC回收时,该异常会遵循.NET异常策略被逐步升级。

分析:逐步升级的后果就是当前应用程序进程崩溃,对于ASP.NET程序来说,就是应用程序池崩溃。

进一步的解决方法

MSDN上的推荐做法是用Task.ContinueWith观察Task中抛出的异常并进行处理,示例代码如下:

var task1 = Task.Factory.StartNew(() =>{    throw new MyCustomException("Task1 faulted.");}).ContinueWith((t) =>    {        Console.WriteLine("I have observed a {0}",            t.Exception.InnerException.GetType().Name);    },    TaskContinuationOptions.OnlyOnFaulted);

小结

应用程序池崩溃的原因总结 —— System.Threading.Tasks.Task中的代码抛出了未处理的异常,由于没有Task.Wait()操作,异常没有被回传给主线程,在GC回收时,发现这个身份不明的异常。然后,这个异常被一级一级上报,直到当前程序进程的最高领导,最高领导为了顾全大局,果然决定与这个异常同归于尽,也就是让整个应用程序池崩溃。。。

时间: 2024-10-23 00:03:35

System.Threading.Tasks.Task 任务引起的IIS应用程序池崩溃的相关文章

项目中使用System.Threading.Timer对象时IIS释放Timer对象的问题

之前的一个项目中使用System.Threading.Timer对象时有没有遇到IIS释放Timer对象的问 题.说实话之前真没遇到过这个问题,就是说我之前定义的timer对象没有释放,运行正常, 回来后我就百度寻找这方面得信息,原来IIS在运行WebApp时对于非静态资源都是自动释放, 而我回头看了看之前写的Web程序,很幸运当时是这么写的: Global.asax文件 private static Timer time; //System.Threading; private static

【进程线程与同步】5.4 System.Threading.Interlocked 为多个线程共享的变量提供原子操作

using System; using System.Threading; internal class Program { private static long _counter = 1; private static void Main() { //下面程序显示两个线程如何并发访问一个名为counter的整形变量,一个线程让他递增5次,一个让他递减5次 Console.WriteLine("原始值:{0}", _counter); var t1 = new Thread(F1);

“System.Threading.ThreadAbortException”类型的异常在 mscorlib.dll 中发生

问题描述 "System.Threading.ThreadAbortException"类型的异常在mscorlib.dll中发生在用VS2005的时候建立站点,第一个界面能进入,但是点击注册进入第二个界面的时候就会出现上面的问题,不知道是哪里错了.输入用户名和密码登陆的时候会ConnectionString属性尚未初始化.连接有问题嘛?做的是一个基于ASP.NET的通讯录. 解决方案 解决方案二:我也遇到这样的情况,没有办法,唉!

timer-关于System.Threading.Timer

问题描述 关于System.Threading.Timer MSDN上的例子: using System; using System.Threading; public class Example { private static Timer ticker; public static void TimerMethod(object state) { Console.Write("."); } public static void Main() { ticker = new Timer

.NET 4 System.Threading.CountdownEvent

在Visual Studio 2010 and .NET Framework 4 Training Kit中有个System.Threading.CountdownEvent的Demo, CountdownEvent类似于Java中有个 CountDownLatch类, 通过CountdownEvent可以在主线程中线程池中的任务运行,主线程要等待线程池中的任务完成之后才能继续.CountdownEvent Class在使用上十分的简单,只要在CountdownEvent的构造函数中传入信号量的

.NET 4 System.Threading.Barrier 类

在Visual Studio 2010 and .NET Framework 4 Training Kit中有个System.Threading.Barrier的Demo,通过Barrier Class我们可以控制线程的运行,做到线程同步的效果. Barrier Class在使用上十分的简单,只要在Barrier的构造函数中传入participantCount(简单的说就是要等待的线程个数),并在要同步的点调用SignalAndWait方法就可以了.线程会在调用SignalAndWait之后暂停

asp.net System.Threading.Timer 如何更新UI

问题描述 我要写一个通知提示,现在想把它做成个用户控件(ascx),用System.Threading.Timer定时去更新数据,更新数据重新绑定Repeater的时候,UI没有更新,GOOGLE了一把没找到答案,都是讲的winform,只好来这里问问,希望大家能解答,用的是System.Threading.Timer,不是微软那个控件,我也知道那个控件可以. 解决方案 解决方案二:能访问到UI吗,如果能访问就有办法更新呀解决方案三:哎,,,这不可能的.Web应用不搞点手段怎么能直接"推&quo

在 System.Threading.ThreadAbortException 中第一次偶然出现的“System.dll”类型的异常

问题描述 在System.Threading.ThreadAbortException中第一次偶然出现的"System.dll"类型的异常线程'<无名称>'(0x9bc)已退出,返回值为0(0x0).线程'<无名称>'(0x138)已退出,返回值为0(0x0).线程'<无名称>'(0xc90)已退出,返回值为0(0x0).线程'<无名称>'(0xa08)已退出,返回值为0(0x0). 解决方案 解决方案二:该回复于2011-11-25 1

在 System.Threading.ThreadAbortException 中第一次偶然出现的“mscorlib.dll”类型的异常

问题描述 winform代码中使用Thread.Abort终止线程遇到以下错误.在System.Threading.ThreadAbortException中第一次偶然出现的"mscorlib.dll"类型的异常.请各位大神帮忙解决以下 解决方案 解决方案二:不会看MSDN吗?Thread.Abort方法.NETFramework4其他版本1(共1)对本文的评价是有帮助-评价此主题在调用此方法的线程上引发ThreadAbortException,以开始终止此线程的过程.调用此方法通常会