AutoResetEvent 的诡异行为
2012-06-13 11:56
218 查看
一.缘起
最近做一个服务端程序,系统运行时,在特定的时候会启动一个通知线程,通知线程执行的方法经简化后就是如下的FirstStateNotifyThread:AutoResetEvent autoResetEvent = new AutoResetEvent(false); private void FirstStateNotifyThread() { this.logger.LogWithTime("进入通知线程"); if (this.autoResetEvent.WaitOne(this.timeoutInMsecs)) { //...... } else { //...... } }
通知线程中用到了AutoResetEvent以等待某个事件完成以达到同步的目的。启动线程的方法如下:
CbGeneric cb = new CbGeneric(this.FirstStateNotifyThread); cb.BeginInvoke(null, null);
开发、调试、测试、部署到自己的测试服务器 都一切运行正常。当部署到正式的服务器上运行时,发现需要启动线程的时刻到来时,没有出现“进入通知线程”的日志,即FirstStateNotifyThread方法没有被执行,线程没有被启动。
二.追踪
于是,我换了一种启动线程的方式,像下面这样:Thread thread = new Thread(new ThreadStart(this.FirstStateNotifyThread)); thread.Start();
情况不仅依旧,而且当要启动线程时,整个进程异常退出了,弹出的提示框内容是“程序遇到问题,将被关闭”。
然后,我再换一种方式:
ThreadPool.QueueUserWorkItem(new WaitCallback(this.FirstStateNotifyThread1) ;
仍然一样,也导致进程退出。
郁闷了,并且只有这台服务器上才会出现,其也是windows 2003 server 系统,是怎么回事了?
接着,我把FirstStateNotifyThread 方法中的逻辑代码全部去掉,只留一句写日志的代码,结果,可以正常执行。就这样不断地增加业务代码,最后问题定位到了autoResetEvent.WaitOne方法,如果注释掉这一句,就OK,开启这一句,就导致执行FirstStateNotifyThread 的线程无法启动。
大概找到问题的位置后,我尝试使用AutoResetEvent的另一个WaitOne重载方法:
autoResetEvent.WaitOne(this.timeoutInMsecs ,false)
使用这个重载方法后,在正式的服务器上也可以顺利的启动FirstStateNotifyThread 线程了。
三.暂时的结论
问题看似解决了,但是问题的根源在哪里了?我用reflector查看了AutoResetEvent的WaitOne方法的源码,一起来看看:[TargetedPatchingOptOut("Performance critical to inline this type of method across NGen image boundaries")] public virtual bool WaitOne(int millisecondsTimeout) { return this.WaitOne(millisecondsTimeout, false); } public virtual bool WaitOne(int millisecondsTimeout, bool exitContext) { if (millisecondsTimeout < -1) throw new ArgumentOutOfRangeException("millisecondsTimeout", Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegOrNegative1")); return this.WaitOne((long) millisecondsTimeout, exitContext); }
第一个WaitOne方法直接调用了第二个重载的WaitOne方法,这没什么问题。焦点在于第一个WaitOne方法标记了TargetedPatchingOptOut这样一个Attribute,查询MSDN知道:TargetedPatchingOptOut是用于指示内联(inline),熟悉C或C++的朋友对这个词应该非常熟悉。根据前面的步步验证,可以肯定的是,在我们正式的服务器上要加载或执行内联了WaitOne的代码镜像时,出现了异常。至于是什么异常,代码中使用try/catch捕获不到。
之后,我又测试了ManualResetEvent,也存在同样的情况。问题的根源可能已经涉及到了CLR或windows程序执行,但还是可以总结一点经验:为了使ManualResetEvent/AutoResetEvent在所有的机器上都能正常运转,请使用带有两个参数的WaitOne方法。
有哪位朋友能知道更多内幕原因的,还望留言不吝赐教,谢谢。
相关文章推荐
- 组织结构配置文件的诡异行为
- IE之诡异行为
- popstate事件在webkit中的诡异行为
- H5中popstate事件的诡异行为
- 路人实拍Waymo无人车:行为诡异,谨慎到让人怀疑人生
- 诡异的编译器行为
- 行为诡异的子查询与非常用谓词ANY/ALL/SOME
- C++复制构造函数的诡异行为研究
- ajax调用action中方法诡异行为
- 前端复习--js中对象的诡异行为
- popstate事件在webkit中的诡异行为
- 阿里巴巴用户行为与广告价值研究
- unity 行为树使用
- 行为驱动开发之二,实施篇
- (行为模式)MEDIATOR——中介者模式
- Strategy模式——行为模式
- 用JavaScript 中onblur()函数判断失去焦点后的行为
- Expression Blend实例中文教程(9) - 行为快速入门Behaviors
- 浅谈jQuery 中的事件冒泡和阻止默认行为
- 支点(行为的一般化)