在ACE中使用epoll的ET模式

本文介绍了一位开发者在Linux下使用ACE_Dev_Poll_Reactor创建服务端程序时遇到的问题,即注册读写事件后,handle_output不断被调用导致CPU占用率100%。原因是ACE_Dev_Poll_Reactor默认使用了epoll的LT模式。为避免修改ACE库内部代码,开发者选择了派生类并重载相关函数,通过在epoll_ctl前设置EPOLLET标志切换到ET模式。尽管需要重载多个函数,开发者对于是否存在更优解决方案持开放态度,期待同行交流探讨。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

用ace做了一个linux下的服务端程序,使用了ACE_Dev_Poll_Reactor。

运行后发现,当注册了socket的读写事件(ACE_Event_Handler::READ_MASK | ACE_Event_Handler::WRITE_MASK)后,handle_output就会不停的被调用,同时cpu达到了100%。

查找原因,原来是ACE_Dev_Poll_Reactor中使用了epoll的LT模式,同时搜索代码,也没有发现ET相关的关键字。

最初的想法是修改ACE_Dev_Poll_Reactor的代码,增加ET的处理。但是我不想修改ace库内部的代码,所以使用了派生的方法,同时感觉到ace结构设计的完美。

 

class CMyReactor : public ACE_Dev_Poll_Reactor

{

....

//重载内部注册回调的接口

int register_handler_i (ACE_HANDLE handle,ACE_Event_Handler *eh,ACE_Reactor_Mask mask)

{

 ACE_TRACE ("ACE_Dev_Poll_Reactor::register_handler_i");

 if (handle == ACE_INVALID_HANDLE
  || mask == ACE_Event_Handler::NULL_MASK)
 {
  errno = EINVAL;
  return -1;
 }

 if (this->handler_rep_.find (handle) == 0)
 {
  // Handler not present in the repository.  Bind it.
  if (this->handler_rep_.bind (handle, event_handler, mask) != 0)
   return -1;

  struct epoll_event epev;
  ACE_OS::memset (&epev, 0, sizeof (epev));
  static const int op = EPOLL_CTL_ADD;

  epev.events  = this->reactor_mask_to_poll_event (mask);
  epev.data.fd = handle;

  if( NET_SETTING.ET_MODE )
  {
   epev.events |= EPOLLET;  // 关键代码,增加ET标识 [1/13/2011 yao]
  }

  if (::epoll_ctl (this->poll_fd_, op, handle, &epev) == -1)
  {
   ACE_ERROR ((LM_ERROR, "%p\n", "epoll_ctl"));
   (void) this->handler_rep_.unbind (handle);
   return -1;
  }
 }
 else
 {
  // Handler is already present in the repository, so register it
  // again, possibly for different event.  Add new mask to the
  // current one.
  if (this->mask_ops_i (handle, mask, ACE_Reactor::ADD_MASK) == -1)
   ACE_ERROR_RETURN ((LM_ERROR, "%p\n", "mask_ops_i"), -1);
 }

 // Note the fact that we've changed the state of the wait_set_,
 // which is used by the dispatching loop to determine whether it can
 // keep going or if it needs to reconsult select().
 // this->state_changed_ = 1;

 return 0;




}

....

}


只要在epoll_ctl 之前增加EPOLLET就可以了搞定了。

如果想要执行,还需要重载几个其他的函数,因为register_handler_i并不是虚函数,所以要从调用register_handler_i的函数开始重载。这里有没有更好的做法,我还不清楚。哪位朋友有更好的做法,欢迎一起研究一下大笑

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值