当前位置:   article > 正文

boost.asio 源码剖析_asio源码分析

asio源码分析

前言

自工作以来一直想看boost库底层代码,但每次都被一大堆宏以及各种模板劝退了,这段时间不怎么忙,系统学习了template后,还是坚持看完了。学习过程中发现有关这部分文章比较少,大多也只是泛泛而谈,所以在此分享下,希望能帮助到大家,如有问题欢迎评论。

我的boost版本为1.7.5
boost版本可以通过引入boost/version.hpp,然后点进去查看

boost.asio设计模式

boost不同于libevent或者muduo ,使用的为前摄器模式。
前摄器和reactor模式很类似,区别在于:reactor是当socket可读时,调用用户回调,由用户调用系统调用读。而前摄器模式是当socket可读时,将数据读取,然后在合适时机,调用用户回调来处理数据。由此可见两者最大的区别在于,用户回调中是否需要io操作。相比reactor,前摄器响应io速度会更快,但回调触发的实时性会弱于reactor,以及实现复杂度也会相比reactor更高。

asio 总述

asio 中主要概念如下

excutor : 如io_contex和io_service,负责任务执行和调度。
operation: 任务类,分为io任务(网络和定时器)和普通函数任务。
service: 提供服务,可以理解为代理类,做不同任务添加的 添加或者修改。

excution类图

首先我们看下io_context的类图关系,可见io_context,继承于execution_context, execution_context中包含service_register, service_register用于注册service,然后将service以头插法的方式构成service链表。

在这里插入图片描述

service

先看下service类关系。
schduler是 任务调度的实现类
reactive_socket_service 用于提供socket相关操作
模板类execution_context_service_base中仅有一个静态数据成员id,模板参数使用子类类型实例化。
由此可见我们可以总结出service用于提供逻辑操作。
在这里插入图片描述

operation

operation也就是我上面说的任务,为scheduler_operation的typedef
descriptor_state 用于和文件描述符绑定,在内部有read,write,err队列,在设置文件描述符监听事件时传入,待epoll返回后从返回事件的ptr中取出,根据返回类型触发不同的io操作。
reactor_op 为io操作任务,该类对象直接添加到descriptor的队列中。reactor_op中有两个函数数据成员:1个用于执行对应的io任务,如读写;另一个保存用户传入的回调,在适当时机将之前io操作的结果传回调。
task_operation 也继承同一基类,该类没有过多作用,仅仅用于做为一个op_quque队尾标记使用。

在这里插入图片描述

有了上面类关系梳理,我们下面走流程。顺序为先任务调度,再任务添加。你也可以先看任务添加再看任务调度。

任务调度

任务调度(事件循环),下面以io_context为例,单线程为例(即一个io_context仅bind一个thread)。
假设我们使用场景为 : 创建io_context对象ioc_ --> 将ioc_.run()运行再另外其一个线程中。

代码分析

流程分两步

构造
  1. 调用基类构造函数创建service_register
  2. 利用service_register创建scheduler ,此时service_register的service链表中插入了第一个service
thread 运行
  1. 线程运行,调用scheduler的run()函数;

在这里插入图片描述
thread_info 为每个线程的独享变量,内部有private_op_queue, 用于临时存储触发事件的descriptor_state,以及完成io读写的reactor_op
在这里插入图片描述
context 为上下文,以链表形式存储context对象,context 的 id为schedule对象的地址,value为this_info , 所以可以根据一个io_context 找到它所有的thread_info,也即可以很容易却修改不同线程的局部operation队列 private_op_queue。
在这里插入图片描述
2)循环调用do_run_one来消费op_queue
代码
[注] : op_queue为scheduler的成员变量

std::size_t scheduler::do_run_one(mutex::scoped_lock& lock,
    scheduler::thread_info& this_thread,
    const boost::system::error_code& ec)
{
  while (!stopped_)
  {
    if (!op_queue_.empty())
    {
      // Prepare to execute first handler from queue.
      operation* o = op_queue_.front();
      op_queue_.pop();
      bool more_handlers = (!op_queue_.empty());

      if (o == &task_operation_)
      {
        task_interrupted_ = more_handlers;

        if (more_handlers && !one_thread_)
          wakeup_event_.unlock_and_signal_one(lock);
        else
          lock.unlock();

        task_cleanup on_exit = { this, &lock, &this_thread };
        (void)on_exit;

        // Run the task. May throw an exception. Only block if the operation
        // queue is empty and we're not polling, otherwise we want to return
        // as soon as possible.
        task_->run(more_handlers ? 0 : -1, this_thread.private_op_queue);
      }
      else
      {
        std::size_t task_result = o->task_result_;

        if (more_handlers && !one_thread_)
          wake_one_thread_and_unlock(lock);
        else
          lock.unlock();

        // Ensure the count of outstanding work is decremented on block exit.
        work_cleanup on_exit = { this, &lock, &this_thread };
        (void)on_exit;

        // Complete the operation. May throw an exception. Deletes the object.
        o->complete(this, ec, task_result);
        this_thread.rethrow_pending_exception();

        return 1;
      }
    }
    else
    {
      wakeup_event_.clear(lock);
      wakeup_event_.wait(lock);
    }
  }

  return 0;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59

伪代码

while(!stop){
	if(op_queue非空){
		//从op_queue中出队一个operation
		if(/*该operation为队尾标志*/){
			if(/*io_context绑定多个线程*/){
				//唤醒一个线程
			}else{
				//解锁
			}
			if(/*op_queue空*/){
				//reactor堵塞
			}else{
				reactor立刻返回
			}
			//将reactor返回的operation添加到op+queue中
		}else{
			//从op中获取执行结果(注意io操作,第一次结果为触发事件类型,第二次为io操作结果)
			//调用op的完成函数(第一次为根据返回事件类型读写数据,第二次为将读写的结果传给用户回调)
		}
		
	}else{
		//让渡出cpu
	}
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24

reactor
在linux系统下为epoll,在windows下为io_cp
reactor.run(),删减了定时器相关逻辑

void epoll_reactor::run(long usec, op_queue<operation>& ops)
{
  // Block on the epoll descriptor.
  epoll_event events[128];
  int num_events = epoll_wait(epoll_fd_, events, 128, timeout);



  for (int i = 0; i < num_events; ++i)
  {
    void* ptr = events[i].data.ptr;
    if (ptr == &interrupter_)
    {

    else
    {
      // The descriptor operation doesn't count as work in and of itself, so we
      // don't call work_started() here. This still allows the scheduler to
      // stop if the only remaining operations are descriptor operations.
      descriptor_state* descriptor_data = static_cast<descriptor_state*>(ptr);
      if (!ops.is_enqueued(descriptor_data))
      {
        descriptor_data->set_ready_events(events[i].events);
        ops.push(descriptor_data);
      }
      else
      {
        descriptor_data->add_ready_events(events[i].events);
      }
    }
  }
}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33

reactor.run()封装了epoll,并将触发了事件的文件描述符fd绑定的descriptor_state,传给thread_info的private_op_queue,本次循环结束后添加到op_queue中。

完整流程如下:

异步任务执行逻辑流程图
在这里插入图片描述

任务添加

向io_context添加任务的方式大致有三种

如async_wirte,async_accept之类
定时器 : 定时器的实现方式和muduo库类似,感兴趣可以直接看muduo库学习下
post() post添加的为普通函数任务

使用过boost编写过网络程序,对下面这三行一定不陌生

socket 用于读写数据
acceptor 用于接受连接
resolver用于域名解析(dns解析)

typedef basic_stream_socket<tcp> socket
typedef basic_socket_acceptor<tcp> acceptor
typedef basic_resolver<tcp> resolver;

  • 1
  • 2
  • 3
  • 4

下面将会通过acceptor来阐述异步io任务添加的全过程,这部分也是个人感觉比较难懂的部分,可能内办法介绍出每一个细节,做好还是能够结合我注解亲自看看代码。

类关系分析

basic_socket_acceptor,内部成员为io_object_impl。io_object_impl使用reactive_socket_service和excutor类型实例化模板。
在这里插入图片描述

流程

流程分两部分

acceptor构造流程

acceptor构造函数

我们可以看知道这里完成了impl的初始化,然后创建了socket用于等待连接。
open : 创建socket_fd,创建descriptor_state,完成scoket_fd和descriptor的绑定以及向epoll监视集合中的注册。
bind: 绑定ip端口
listen :赋予socket监听能力

在这里插入图片描述

io_object_impl构造类

IoObjectService<Service , execution>为reactive_socket_service< tcp >
首先利用user_sevice()从传入的io_context的service_regitser获取reactive_socket_service< tcp >,如果没有则创建并添加到service_regitser中。然后调用reactive_socket_service<>基类方法初始化implemetation_,初始状态为无效状态。
在这里插入图片描述

implemtation 类定义
在这里插入图片描述

async_accept

acceptor初始化完毕后,我们需要调用async_accept开始异步accept。
在这里插入图片描述

1部分为模板参数列表,简单来说就是template< typename MoveAcceptHandler = void >
2部分 为 auto,返回值类型为return返回值的类型。
handler为bind返回的函数对象(用户传入回调的函数对象)
调用aync_initiate 创建 initiate_async_move_accept对象(该对象负责添加异步任务逻辑)

async_initiate函数

Initiation : 为 initiate_async_move_accept之类用于做事件分发的
ComletetionToken : 我们可以简单理解为用户回调。

在这里插入图片描述

上面completion作用暂时不是很清楚,只知道包裹用户回调,建立异步回调和异步结果的联系。

方框标出部分实现逻辑为(1)调用initiation的转移构造函数后,(2)调用initiation重载后的()运算符。

该例子中调用 initiate_async_move_accept的()运算符
在这里插入图片描述
impl_为最开始介绍的io_object_impl
get_service()获得的为reactive_socket_service

所以接下来调用时reactive_socket_service< tcp >下的async_accept
在这里插入图片描述

  • 创建async operation

1部分 : 创建reactive_socket_accept_op对象,实际上在该对象中保存了2个函数,(1)执行io操作的函数,(2)是用户传入的回调

reactive_socket_accept_op 多层继承,最上层基类scheduler_operation 类定义大致如下:

(1) reactive_socket_Accept_base基类构造
在这里插入图片描述
(2)
在这里插入图片描述
至此我们可以看出,用户回调保存在顶级基类operation中,执行io操作的回调函数保存在perform_func中。

  • async operation 添加

2部分 : 添加该opeation到对应的socket_fd所绑定的descriptor_state的读操作队列中。

在这里插入图片描述
该代码逻辑为 : 如果peer_is_open ,则直接填入error_code,将该operation 通过reactor_添加到io_context的op_queue中,由事件循环直接执行用户回调;
如果peer_is_open为false, 调用reactor_op添加该opeation到对应的socket_fd所绑定的 descriptor_state的read操作队列中。

start_op代码
在这里插入图片描述
至此async_Accept 添加任务结束,等待客户端连接到达触发用户回调。

Post源码剖析

Post是asio最常用的函数之一,可以将普通函数任务添加到eventloop中。这部分流程不复杂,主要难点是模板相关的内容。下面为了尽可能详细,可能导致条理不是特别清晰,希望大家能给提点建议,帮助后续优化文章结构。

post入口代码如下:

在这里插入图片描述

这里和上文一样,就是创建initiate_post对象,然后调用initiate_post的operator(),将handler,以及this指针作为传入参数。

initiate_post

代码如下
在这里插入图片描述

代码大致上可以分为三部分

  • 1部分以handler作为传入对象,创建非const属性的handler2
  • 2部分根据handler类型实例化operation类型
  • 3部分将该operation添加到eventloop的任务队列中。

下面对这三部分展开讲

第一部分
detail::non_const_lvalue< LegacyCompletionHandler >

在这里插入图片描述

上面拷贝构造函数中实际上就是对传入参数t进行了强制类型转换(如果T为引用,则强转为T的右值引用,否则强转为T的引用)

conditional模板类

在这里插入图片描述

  • 1为conditional主模板
  • 2 为conditional模板类的偏特化模板
    当我们实例化模板conditional时,如果 _Cond 是false,则匹配偏特化版本,则该condital类实例化类的type为第三个类型参数*** _Iffalse***;_Cond 非false,则匹配主模板,type为第二个类型参数*** _Iftrue***。
std::is_same::value

在这里插入图片描述

上面我们可以知道当我们用两个两个同样的类型实例化is_same时,is_same匹配ture_type;其他情况匹配false_type

ture_type,false_type 为使用如下类型参数实例化 integral_constant模板的typedef。
在这里插入图片描述

在这里插入图片描述

这段代码考察了非类型模板参数
第一个方框:类型参数_Tp
第二个方框 : 实例化时需要填入一个_Tp的值
所以上文false_type::value 为false。

std::decay

用于退化类型,如T 为int&,我们std::decay< int& >::type 得到类型int。
详细介绍看下面链接
std::decay链接

第二部分
completion_handler

完整代码如下

template <typename Handler, typename IoExecutor>
class completion_handler : public operation
{
public:
  // ptr类定义
  BOOST_ASIO_DEFINE_HANDLER_PTR(completion_handler);

  completion_handler(Handler& h, const IoExecutor& io_ex)
    : operation(&completion_handler::do_complete),
      handler_(BOOST_ASIO_MOVE_CAST(Handler)(h)),
      work_(handler_, io_ex)
  {
  }

  static void do_complete(void* owner, operation* base,
      const boost::system::error_code& /*ec*/,
      std::size_t /*bytes_transferred*/)
  {
    // Take ownership of the handler object.
    completion_handler* h(static_cast<completion_handler*>(base));
    ptr p = { boost::asio::detail::addressof(h->handler_), h, h };

    BOOST_ASIO_HANDLER_COMPLETION((*h));

    // Take ownership of the operation's outstanding work.
    handler_work<Handler, IoExecutor> w(
        BOOST_ASIO_MOVE_CAST2(handler_work<Handler, IoExecutor>)(
          h->work_));

    Handler handler(BOOST_ASIO_MOVE_CAST(Handler)(h->handler_));
    p.h = boost::asio::detail::addressof(handler);
    p.reset();

    // Make the upcall if required.
    if (owner)
    {
      fenced_block b(fenced_block::half);
      BOOST_ASIO_HANDLER_INVOCATION_BEGIN(());
      w.complete(handler, handler);
      BOOST_ASIO_HANDLER_INVOCATION_END;
    }
  }

private:
  Handler handler_;
  handler_work<Handler, IoExecutor> work_;
};
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
BOOST_ASIO_DEFINE_HANDLER_PTR展开

struct ptr是completion_handler辅助类,作用是根据completion_handler绑定的handler类型选择不同的allocator为completion_handler开辟一段空间,但不使用构造函数。下面将详细介绍allocate实现。

展开代码如下

  struct ptr \
  { \
    Handler* h; \
    op* v; \
    op* p; \
    ~ptr() \
    { \
      reset(); \
    } \
    static op* allocate(Handler& handler) \
    { \
      typedef typename ::boost::asio::associated_allocator< \
        Handler>::type associated_allocator_type; \
      typedef typename ::boost::asio::detail::get_hook_allocator< \
        Handler, associated_allocator_type>::type hook_allocator_type; \
      BOOST_ASIO_REBIND_ALLOC(hook_allocator_type, op) a( \
            ::boost::asio::detail::get_hook_allocator< \
              Handler, associated_allocator_type>::get( \
                handler, ::boost::asio::get_associated_allocator(handler))); \
      return a.allocate(1); \
    } \
    void reset() \
    { \
      if (p) \
      { \
        p->~op(); \
        p = 0; \
      } \
      if (v) \
      { \
        typedef typename ::boost::asio::associated_allocator< \
          Handler>::type associated_allocator_type; \
        typedef typename ::boost::asio::detail::get_hook_allocator< \
          Handler, associated_allocator_type>::type hook_allocator_type; \
        BOOST_ASIO_REBIND_ALLOC(hook_allocator_type, op) a( \
              ::boost::asio::detail::get_hook_allocator< \
                Handler, associated_allocator_type>::get( \
                  *h, ::boost::asio::get_associated_allocator(*h))); \
        a.deallocate(static_cast<op*>(v), 1); \
        v = 0; \
      } \
    } \
  } \
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
associated_allocator

associated_allocator::get作用:如果函数对象handler中有定义自己的allocator则获得该类型的allocator对象,否则返回std::allocate< void > 对象。模板associated_allocator_impl为associated_allocator的实现。

template <typename T, typename E, typename = void>
struct associated_allocator_impl
{
  typedef E type;

  static type get(const T&, const E& e) BOOST_ASIO_NOEXCEPT
  {
    return e;
  }
};
//模板第三方参数为void,且T中定义了allocator_type,则走偏特化版本
template <typename T, typename E>
struct associated_allocator_impl<T, E,
  typename void_type<typename T::allocator_type>::type>
{
  typedef typename T::allocator_type type;

  static type get(const T& t, const E&) BOOST_ASIO_NOEXCEPT
  {
    return t.get_allocator();
  }
};

//associated_allocator模板Allocator默认类型参数为std::allocator<void>
template <typename T, typename  = std::allocator<void> >
struct associated_allocator
{
  typedef typename detail::associated_allocator_impl<T, Allocator>::type type;

  static type get(const T& t,
      const Allocator& a = Allocator()) BOOST_ASIO_NOEXCEPT
  {
    return detail::associated_allocator_impl<T, Allocator>::get(t, a);
  }
};
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
associated_allocator_impl实例化类型确认

上文可见调用如下 detail::associated_allocator_impl<T, Allocator>::get(t, a)
可见第一个类型参数为T,第二个参数为Allocator。优先去尝试匹配associated_allocator_impl的偏特化版本,代码中可见第三个参数为void_type< typename T::allocator_type>::type>, void_type<>::type 类型始终为void。如果T有allocator_type类型,则associated_allocator_impl实例化为偏特化版本,否则由于sfinae丢弃偏特化版本,选择主模板版本。

associated_allocator::type : 如果handler定义了allocator_type类型,则为handler::handler;否则为
std::allocator< void >

get_hook_allocator

get_hook_allocator为利用模板实现的一个hook。

	  //hook_allocator主模板
      template <typename Handler, typename T>
      class hook_allocator
      {
      public:
        typedef T value_type;

        template <typename U>
        struct rebind
        {
          typedef hook_allocator<Handler, U> other;
        };

        explicit hook_allocator(Handler &h)
            : handler_(h)
        {
        }

        template <typename U>
        hook_allocator(const hook_allocator<Handler, U> &a)
            : handler_(a.handler_)
        {
        }

        T *allocate(std::size_t n)
        {
          return static_cast<T *>(
              boost_asio_handler_alloc_helpers::allocate(sizeof(T) * n, handler_));
        }

        void deallocate(T *p, std::size_t n)
        {
          boost_asio_handler_alloc_helpers::deallocate(p, sizeof(T) * n, handler_);
        }

        // private:
        Handler &handler_;
      };
		
	  //hook_allocator偏特化版本
      // 类型void不能够分配内存,所以该版本不应该有allocate和deallocate方法
      template <typename Handler>
      class hook_allocator<Handler, void>
      {
      public:
        typedef void value_type;

        template <typename U>
        struct rebind
        {
          typedef hook_allocator<Handler, U> other;
        };

        explicit hook_allocator(Handler &h)
            : handler_(h)
        {
        }

        template <typename U>
        hook_allocator(const hook_allocator<Handler, U> &a)
            : handler_(a.handler_)
        {
        }

        // private:
        Handler &handler_;
      };

      template <typename Handler, typename Allocator>
      struct get_hook_allocator
      {
        typedef Allocator type;

        static type get(Handler &, const Allocator &a)
        {
          return a;
        }
      };

      template <typename Handler, typename T>
      struct get_hook_allocator<Handler, std::allocator<T>>
      {
        typedef hook_allocator<Handler, T> type;

        static type get(Handler &handler, const std::allocator<T> &)
        {
          return type(handler);
        }
      };
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89

上面代码我们可以看到get_hook_allocator 偏特化版本是当第二个类型参数为std::allocate< T >时, 用T作为一个类型参数实例化hook_allocator模板。如果此时我们使用std::allocator< void >作为get_hook_allocator 的第二个类型参数,则匹配hook_allocator对应其偏特化版本。

在上面这些基础上我们,走一遍completion_handler::ptr的allocate流程。

completion_handler allocate::ptr::allocate流程

Handler为std::bind返回的可调度对象,无内置allocator类型和excutor_type。

  • associated_allocator_type 为std::allocator< void >
  • hook_allocator_type 为 hook_allocator<Handler, void>
  • BOOST_ASIO_REBIND_ALLOC(hook_allocator_type, op)创建hook_allocator<Handler, void>::rebind::hook_allocator<Handler, U> ,U为 completion_handler 的对象a。
  • 调用a.allocate()即可获得completion_handler大小的内存。
a.allocate()流程

T为completion_handler,该allocate返回一个开辟的内存地址。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

thread_info,在调用run时添加到thread_info栈中
在这里插入图片描述
detail::thread_context::top_of_thread_call_stack()找到栈顶的thread_info

在这里插入图片描述
看到下面这部分代码可能会不清楚设计目的。这里是boost的内存管理,既减少了new小内存块产生的内存碎片;又复用了内存,减少了底层malloc的调用次数,可以说是一举两得。

内存分配具体代码如下:
在这里插入图片描述
伪代码如下

  template <typename Purpose>
  static void* allocate(Purpose, thread_info_base* this_thread,
      /*分配字节数size*/)
  {
  	//chunks 为boost自定义一个内存块单元
  	//下面代码为计算所需chunk的数量(方式为向上取整)
    std::size_t chunks = (size + chunk_size - 1) / chunk_size;

    if (/*this_thread->reusable_memory_对应purpose分配了内存*/)
    {

      if (/*需要的字节数size<=已经分配的内存大小*/)
      {
 		//返回这块内存地址
      }
	  /*需要的字节数size > 已经分配的内存大小*/
      //删除该内存
    }

	//根据chunk数开配对应大小字节内存,返回内存地址
  }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  template <typename Purpose>
  static void deallocate(Purpose, thread_info_base* this_thread,
      void* pointer, std::size_t size)
  {
    if (/*pointer指向内存size 合适*/ )
    {
      if (/*this_thread->reusable_memory_[Purpose::mem_index]未分配内存*/)
      {

        //将这部分内存交给this_thread->reusable_memory_[Purpose::mem_index]
        return;
      }
    }
	/*pointer指向内存size 过大*/
    //直接删除pointer指向内存
  }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16

UCHAR_MAX

接下来我们回到io_context::initiate_post中
在这里插入图片描述
这里我们可以创建了ptr对象,以及分配了completion_handler大小的小并存储再p.v中,然后调用new对p.v使用completion_handler的构造函数初始化内存,内存地址赋值给p.p,至此一个包装handler为operation对象完毕。

new的三种使用方法

第三部分

添加operation对象对象到sheduler中
在这里插入图片描述
根据代码可知,当evnetloop为单线程情况下,该operation对象直接添加到this_thread->private_op_Queue中,多线程情况下添加到op_queue中
在这里插入图片描述
至此post流程结束,普通函数任务添加到了eventloop中。

completion_handler完成逻辑

上文已经将包裹函数对象handler的operation添加到了eventloop中。eventloop处理operation,调用completion_handler.do_complete方法。

构造completion_handler时,我们同时初始化了成员handler_work<Handler, IoExecutor> work_,handler_work的作用是如果Handler中没定义executor_type类型,则直接调用用户回调。
在这里插入图片描述

completion_handler<>::do_complete

右值引用

  static void do_complete(void* owner, operation* base,
      const boost::system::error_code& /*ec*/,
      std::size_t /*bytes_transferred*/)
  {
    // 对base类型恢复成completion_handler对象指针
    completion_handler* h(static_cast<completion_handler*>(base));
    ptr p = { boost::asio::detail::addressof(h->handler_), h, h };

    BOOST_ASIO_HANDLER_COMPLETION((*h));

    // 右值引用知识点,使用w获取h->work对象的控制权
    handler_work<Handler, IoExecutor> w(
        BOOST_ASIO_MOVE_CAST2(handler_work<Handler, IoExecutor>)(
          h->work_));

	//  同上
    Handler handler(BOOST_ASIO_MOVE_CAST(Handler)(h->handler_));
    p.h = boost::asio::detail::addressof(handler);
    //释放内存空间
    p.reset();

    if (owner)
    {
	  //调用回调,执行用户回调
      w.complete(handler, handler);

    }
  }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
handler_work模板类

对该模板还有部分没有搞清楚如何走dispatch分支。经过debug测试std::bind返回的handler不走dispatch分支。后续研究清楚再详细更新内容。

//主模板
template <typename Handler, typename IoExecutor, typename = void>
class handler_work :
  handler_work_base<IoExecutor>,
  handler_work_base<typename associated_executor<
      Handler, IoExecutor>::type, IoExecutor>
{
public:
  typedef handler_work_base<IoExecutor> base1_type;
  typedef handler_work_base<typename associated_executor<
    Handler, IoExecutor>::type, IoExecutor> base2_type;

  handler_work(Handler& handler, const IoExecutor& io_ex) BOOST_ASIO_NOEXCEPT
    : base1_type(0, 0, io_ex),
      base2_type(boost::asio::get_associated_executor(handler, io_ex), io_ex)
  {
  }

  template <typename Function>
  void complete(Function& function, Handler& handler)
  {
    if (!base1_type::owns_work() && !base2_type::owns_work())
    {
      boost_asio_handler_invoke_helpers::invoke(function, handler);
    }
    else
    {
      base2_type::dispatch(function, handler);
    }
  }
};


//偏特化版本
template <typename Handler, typename IoExecutor>
class handler_work<
    Handler, IoExecutor,
    typename enable_if<
      is_same<
        typename associated_executor<Handler,
          IoExecutor>::asio_associated_executor_is_unspecialised,
        void
      >::value
    >::type> : handler_work_base<IoExecutor>
{
public:
  typedef handler_work_base<IoExecutor> base1_type;

  handler_work(Handler&, const IoExecutor& io_ex) BOOST_ASIO_NOEXCEPT
    : base1_type(0, 0, io_ex)
  {
  }

  template <typename Function>
  void complete(Function& function, Handler& handler)
  {
    if (!base1_type::owns_work())
    {
      boost_asio_handler_invoke_helpers::invoke(function, handler);
    }
    else
    {
      base1_type::dispatch(function, handler);
    }
  }
};
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66

completion_handler成员变量 work_,实例化handler_work<Handler, IoExecutor>,该实例匹配偏特化版本

handler_work_base< IoExecutor >
//主模板
template <typename Executor, typename CandidateExecutor = void,
    typename IoContext = io_context,
    typename PolymorphicExecutor = executor, typename = void>
class handler_work_base
{
public:
  explicit handler_work_base(int, int, const Executor& ex) BOOST_ASIO_NOEXCEPT
    : executor_(boost::asio::prefer(ex, execution::outstanding_work.tracked))
  {
  }

  template <typename OtherExecutor>
  handler_work_base(const Executor& ex,
      const OtherExecutor&) BOOST_ASIO_NOEXCEPT
    : executor_(boost::asio::prefer(ex, execution::outstanding_work.tracked))
  {
  }

  handler_work_base(const handler_work_base& other) BOOST_ASIO_NOEXCEPT
    : executor_(other.executor_)
  {
  }

#if defined(BOOST_ASIO_HAS_MOVE)
  handler_work_base(handler_work_base&& other) BOOST_ASIO_NOEXCEPT
    : executor_(BOOST_ASIO_MOVE_CAST(executor_type)(other.executor_))
  {
  }
#endif // defined(BOOST_ASIO_HAS_MOVE)

  bool owns_work() const BOOST_ASIO_NOEXCEPT
  {
    return true;
  }

  template <typename Function, typename Handler>
  void dispatch(Function& function, Handler& handler)
  {
    execution::execute(
        boost::asio::prefer(executor_,
          execution::blocking.possibly,
          execution::allocator((get_associated_allocator)(handler))),
        BOOST_ASIO_MOVE_CAST(Function)(function));
  }

private:
  typedef typename decay<
      typename prefer_result<Executor,
        execution::outstanding_work_t::tracked_t
      >::type
    >::type executor_type;

  executor_type executor_;
};

//偏特化版本
template <typename Executor, typename IoContext, typename PolymorphicExecutor>
class handler_work_base<Executor, void, IoContext, PolymorphicExecutor,
    typename enable_if<
      is_same<
        Executor,
        typename IoContext::executor_type
      >::value
    >::type>
{
public:
  explicit handler_work_base(int, int, const Executor&)
  {
  }

  bool owns_work() const BOOST_ASIO_NOEXCEPT
  {
    return false;
  }

  template <typename Function, typename Handler>
  void dispatch(Function& function, Handler& handler)
  {
    boost_asio_handler_invoke_helpers::invoke(function, handler);
  }
};
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 上文中我们使用handler_work_base< IoExecutor >实例化模板,所以模板类型参数IoContext 使用默认类型io_context,最后一个参数为void。
  • is_same<Executor, typename IoContext::executor_type>::value 为ture, enable_if<>::value为void,所以实例化为偏特化版本。注意该特化版本的dispatch也调用了boost_asio_handler_invoke_helpers::invoke(function, handler)
  • owns_work()返回false。
boost_asio_handler_invoke_helpers::invoke

在这里插入图片描述
在这里插入图片描述

在这里我们可以暂时得出结论:如可调度对象没有定义executor_type类型的话,complete_handler::do_complete 始终调用boost_asio_handler_invoke_helpers::invoke(function, handler),即立刻调用用户传入回调。

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/笔触狂放9/article/detail/740729
推荐阅读
相关标签
  

闽ICP备14008679号