2008年10月30日星期四

记录一个bug

最近改的一个bug比较麻烦.症状是一个.NET程序调用我们写的Native code出错,死锁了.用WinDbg观察,发现是死在.NET层中用于垃圾收集的一个线程中,叫Finalize thread,专门用于收集不用的unmanaged的资源.下面这篇文章具体描述Finalize thread的死锁.

http://dotnetdebug.net/2005/06/22/blocked-finalizer-thread/

我对.NET完全是白痴,只用C#写过几个demo程序用来验证API,看着这情形就晕了.不过还是可以看到,一个生存在STA套间的线程(大概是主线程),在等Finalize thread完成,而Finalize thread则在等待一个STA的COM组件的反应.于是死锁发生了.

现在在回忆的时候,觉得这一切再明显不过.不过在调查这个bug过程中,却觉得非常困难,原因有2,首先是不懂.NET,看着这些就有障碍.再者,这个项目是在已有代码的基础上继续开发,对原有的代码不熟悉,还有些程序根本就没有源代码,比如调用我们Native code的.NET程序.

问题在于在使用那个COM组件前后,调用了CoInitialize(NULL)和CoUninitialize(),实际这个是不必要的,因为在每个线程起来时都会调用,这里其实只是重复调用,当时没有多想,只是为了保险写了这样两句.而调用这段的Native Code的线程则是在MTA中的,问题就这样出现了.也有文章说这个事情的.

http://blogs.msdn.com/benkuhn/archive/2006/09/15/756401.aspx

大概是说CoInitialize和CoUninitialize的nest call,如果是进入不同的模式,会引起COM库的引用计数混乱.去掉这一对对CoInitialize/CoUninitialize,程序正常.

非常想研究下.NET的内部架构,这样的错误就不会犯了.

没有评论: