前言

自工作以来一直想看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);elselock.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);elselock.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;
}

伪代码

while(!stop){if(op_queue非空){//从op_queue中出队一个operationif(/*该operation为队尾标志*/){if(/*io_context绑定多个线程*/){//唤醒一个线程}else{//解锁}if(/*op_queue空*/){//reactor堵塞}else{reactor立刻返回}//将reactor返回的operation添加到op+queue中}else{//从op中获取执行结果(注意io操作,第一次结果为触发事件类型,第二次为io操作结果)//调用op的完成函数(第一次为根据返回事件类型读写数据,第二次为将读写的结果传给用户回调)}}else{//让渡出cpu}
}

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);}}}
}

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;

下面将会通过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_;
};
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; \} \} \} \
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);}
};
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);}};

上面代码我们可以看到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数开配对应大小字节内存,返回内存地址}
  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指向内存}

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);}}
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);}}
};

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);}
};
  • 上文中我们使用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),即立刻调用用户传入回调。

boost.asio 源码剖析相关推荐

  1. Boost.ASIO源码:从async_write看ASIO的异步IO逻辑

    async_write有两个对外接口: template <typename AsyncWriteStream, typename Allocator, typename WriteHandle ...

  2. boost源码剖析之:Tuple Types(rev#2)

    boost源码剖析之:Tuple Types(rev#2)   刘未鹏(pongba) C++的罗浮宫(http://blog.csdn.net/pongba)   Note: 并非新作,04年曾放在 ...

  3. boost源码剖析之:多重回调机制signal(下)

    boost源码剖析之:多重回调机制signal(下) 刘未鹏 C++的罗浮宫(http://blog.csdn.net/pongba) 在本文的上篇中,我们大刀阔斧的剖析了signal的架构.不过还有 ...

  4. boost源码剖析之:多重回调机制signal(上)

    boost源码剖析之:多重回调机制signal(上) 刘未鹏 C++的罗浮宫(http://blog.csdn.net/pongba) boost库固然是技术的宝库,却更是思想的宝库.大多数程序员都知 ...

  5. boost源码剖析之:泛型函数指针类boost::function(rev#3)

    boost源码剖析之:泛型函数指针类boost::function(rev#3) 刘未鹏 C++的罗浮宫(http://blog.csdn.net/pongba)   Note: 并非新作,03年曾放 ...

  6. boost源码剖析之:boost::multi_array

    boost源码剖析之:boost::multi_array 谢轩 刘未鹏 C++的罗浮宫(http://blog.csdn.net/pongba) Note: 并非新作,是以前和老朋友谢轩写的,也可以 ...

  7. boost源码剖析之:泛型编程精灵type_traits(rev#2)

    boost源码剖析之:泛型编程精灵type_traits(rev#2) 刘未鹏 C++的罗浮宫(http://blog.csdn.net/pongba) 动机 使用traits的动机一般有三种,分派. ...

  8. boost源码剖析之:泛型指针类any之海纳百川(rev#2)

    boost源码剖析之:泛型指针类any之海纳百川(rev#2) 刘未鹏 C++的罗浮宫(http://blog.csdn.net/pongba) 动机 C++是强类型语言,所有强类型语言对类型的要求都 ...

  9. 老李推荐:第14章4节《MonkeyRunner源码剖析》 HierarchyViewer实现原理-装备ViewServer-端口转发 1...

    老李推荐:第14章4节<MonkeyRunner源码剖析> HierarchyViewer实现原理-装备ViewServer-端口转发 在初始化HierarchyViewer的实例过程中, ...

  10. JS魔法堂:mmDeferred源码剖析

    一.前言 avalon.js的影响力愈发强劲,而作为子模块之一的mmDeferred必然成为异步调用模式学习之旅的又一站呢!本文将记录我对mmDeferred的认识,若有纰漏请各位指正,谢谢.项目请见 ...

最新文章

  1. Spark UDAF用户自定义聚合函数
  2. [deviceone开发]-do_Dialog的基本使用示例
  3. 互联网1分钟 | 1009
  4. springmvc学习(一)
  5. 微软想将新版Edge浏览器引入Linux
  6. python怎么创建txt文件啊_python根据txt文本批量创建文件夹
  7. php数组转为js json,javascript-将数组php转换为JSON时出错
  8. java学习之(内部类)
  9. android mkv 字幕乱码,Android 西班牙语字幕乱码 字符编码
  10. SpringBoot2.0之七 实现页面和后台代码的热部署
  11. 瑞星09年第一季度安全报告:8亿网民遭木马攻击
  12. VC下__func__未定义,改用__FUNCTION__
  13. linux快速查看连接到服务器的ip
  14. yii2 restful web服务[格式响应]
  15. 中国信通院沈滢:字体开源协议——OFL V1.1介绍及合规要点分析
  16. 黑鲨3怎么安装鸿蒙系统,黑鲨u盘重装系统步骤
  17. 如何制作六一儿童节答题测试H5页面?
  18. linux虚拟机+显卡驱动,ubuntu12.4优化android虚拟机和安装intel显卡驱动
  19. 2013年9月中秋云南昆明、丽江、泸沽湖、香格里拉、梅里雪山、虎跳峡之旅
  20. VSCode这13款插件也太好用了

热门文章

  1. 【转】Iphone4/4S验机教程
  2. 右下角弹窗 html 怎么写,右下角弹窗广告.html
  3. javascript学习之 小案例 (29)——js时钟
  4. 关于CAN总线的布线
  5. c语言程序如何防止盗用,如何用C语言程序盗取QQ密码
  6. 操作手册与用户手册的区别
  7. C语言生成负指数分布,泊松分布与负指数分布的关系
  8. elastic APM针对java应用的高阶用法(java agent)
  9. 好男07演唱会将开唱 劲歌热舞点燃盛夏激情
  10. 服务器系统有哪些,各有什么特点?