Linux下,Boost.Asio是如何通过epoll做到IO异步的

时间:2022-07-02 05:55:01
背景:epoll的实现是基于回调的,如果fd有期望的事件发生就通过回调函数将其加入epoll就绪队列中,用户针对该队列中的文件句柄发起相应操作,如read等,此时数据真正才会开始从内核buffer写入应用buffer中,整个过程是一种同步IO。而Boost.Asio采用Proactor模式实现了异步IO,也就是说用户在发起async_read后,可以去进行其它操作,内核将数据从内核buffer写入应用buffer,最后会通知其数据已经拷贝完毕。
问题:Boost.Asio在Linux下封装epoll这种同步接口是如何做到异步IO的。看了源代码,有async_read,但没有看出其中的奥妙,请指点,谢谢

2 个解决方案

#1


看io_service类里的成员impl_, 贴几段代码你应该就明白了,

// io_service.hpp
typedef class task_io_service io_service_impl;
...
class io_service: private noncopyable
{
private:
  typedef detail::io_service_impl impl_type;
  ...
  impl_type& impl_;
};


// detail/task_io_service.hpp
#include <boost/asio/detail/reactor_fwd.hpp>
...
class task_io_service
  : public boost::asio::detail::service_base<task_io_service>
{
  ...
  reactor* task_;
  ...
};



// detail/reactor_fwd.hpp
typedef class epoll_reactor reactor;



// detail/epoll_reactor.hpp
class epoll_reactor
  : public boost::asio::detail::service_base<epoll_reactor>
{
  ...
private:
  ...
BOOST_ASIO_DECL static int do_epoll_create();
  ...
};



// detail/impl/epoll_reactor.ipp
int epoll_reactor::do_epoll_create()
{
  ...
  if (fd == -1 && (errno == EINVAL || errno == ENOSYS))
  {
    fd = epoll_create(epoll_size);
    if (fd != -1)
      ::fcntl(fd, F_SETFD, FD_CLOEXEC);
  }
  ...
  return fd;
}


detail/impl/epoll_reactor.ipp 里有很多epoll的封装

#2


多谢回复,我好好整理一下

#1


看io_service类里的成员impl_, 贴几段代码你应该就明白了,

// io_service.hpp
typedef class task_io_service io_service_impl;
...
class io_service: private noncopyable
{
private:
  typedef detail::io_service_impl impl_type;
  ...
  impl_type& impl_;
};


// detail/task_io_service.hpp
#include <boost/asio/detail/reactor_fwd.hpp>
...
class task_io_service
  : public boost::asio::detail::service_base<task_io_service>
{
  ...
  reactor* task_;
  ...
};



// detail/reactor_fwd.hpp
typedef class epoll_reactor reactor;



// detail/epoll_reactor.hpp
class epoll_reactor
  : public boost::asio::detail::service_base<epoll_reactor>
{
  ...
private:
  ...
BOOST_ASIO_DECL static int do_epoll_create();
  ...
};



// detail/impl/epoll_reactor.ipp
int epoll_reactor::do_epoll_create()
{
  ...
  if (fd == -1 && (errno == EINVAL || errno == ENOSYS))
  {
    fd = epoll_create(epoll_size);
    if (fd != -1)
      ::fcntl(fd, F_SETFD, FD_CLOEXEC);
  }
  ...
  return fd;
}


detail/impl/epoll_reactor.ipp 里有很多epoll的封装

#2


多谢回复,我好好整理一下