深圳夜归人

繁华的都市,有谁记得我们的脚步?

  博客园 :: 首页 :: 博问 :: 闪存 :: 新随笔 :: 联系 :: 订阅 订阅 :: 管理 ::
仔细研究了一下,如果要使用ACE_TP_Reactor,则不宜对同一个ACE_Event_Handler同时注册SOCKET和其它事件,因为ACE_TP_Reactor只保证“不会有2个线程同时调用同一个Event_Handler的SOCKET事件处理器”。

上次我修改了一个版本,让它能同时处理SOCKET事件和TIMER事件,不过在压力测试下还是出了问题。原因是当客户端主动断线时,peer().get_handler()将返回一个无效值,这时正在处理handle_close但还没有完成,另一线程却获取了TIMER事件,原有的判断无法处理这种SOCKET句柄失效情况,所以handle_timeout被调用,而另一调用handle_close的线程这时可能正好把对象析构掉了,造成段错误。更隐蔽的情况,是对象被析构了,事件分派程序却在调用它的get_handler方法,出现机率小,但却致命,所以那个做法是有很大问题的。

唯一的解决是把原来的suspend_*和resume_*处理SOCKET句柄改为处理ACE_Event_Handler*,这将保证“不会有2个线程同时调用同一个Event_Handler的处理方法”,不过修改太多,而且我现在觉得使用反应器线程池在很多场合不太适合。想一想这种情况:服务器要定时向客户端发送探测消息,假如刚要调用发送时,处理器被另一线程析构了(可能是客户端断线引起的),就会有一个段错误。加一把“大锁”?还不如做单线程。

大概没有更好的理由一定要使用ACE_TP_Reactor,好点的做法是使用单线程的Reactor,把收到的“消息”放入一个同步队列,由一个线程池去处理,处理的结果(要发送的消息)放入别一同步队列,使用某种激发机制(信号,定时器,通知)使Reactor调用处理器去发送。如果要发送定时探测,可以直接从Reactor启动一个定时器,由于是单线程的,不需要处理那么些麻烦事。

上次见有人说,单线程的Reactor 可能在处理SOCKET时阻塞,影响所有客户响应,我测试时并没有遇到这种情况,可能是我设置了NON_BLOCKING的缘故。
posted on 2005-08-30 18:02  cpunion  阅读(2839)  评论(3编辑  收藏  举报