自工作以来一直想看boost库底层代码,但每次都被一大堆宏以及各种模板劝退了,这段时间不怎么忙,系统学习了template后,还是坚持看完了。学习过程中发现有关这部分文章比较少,大多也只是泛泛而谈,所以在此分享下,希望能帮助到大家,如有问题欢迎评论。
我的boost版本为1.7.5
boost版本可以通过引入boost/version.hpp,然后点进去查看
boost不同于libevent或者muduo ,使用的为前摄器模式。
前摄器和reactor模式很类似,区别在于:reactor是当socket可读时,调用用户回调,由用户调用系统调用读。而前摄器模式是当socket可读时,将数据读取,然后在合适时机,调用用户回调来处理数据。由此可见两者最大的区别在于,用户回调中是否需要io操作。相比reactor,前摄器响应io速度会更快,但回调触发的实时性会弱于reactor,以及实现复杂度也会相比reactor更高。
asio 中主要概念如下
excutor : 如io_contex和io_service,负责任务执行和调度。
operation: 任务类,分为io任务(网络和定时器)和普通函数任务。
service: 提供服务,可以理解为代理类,做不同任务添加的 添加或者修改。
首先我们看下io_context的类图关系,可见io_context,继承于execution_context, execution_context中包含service_register, service_register用于注册service,然后将service以头插法的方式构成service链表。
先看下service类关系。
schduler是 任务调度的实现类
reactive_socket_service 用于提供socket相关操作
模板类execution_context_service_base中仅有一个静态数据成员id,模板参数使用子类类型实例化。
由此可见我们可以总结出service用于提供逻辑操作。
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()运行再另外其一个线程中。
流程分两步
- 调用基类构造函数创建service_register
- 利用service_register创建scheduler ,此时service_register的service链表中插入了第一个service
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;
}
伪代码
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
}
}
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构造函数
我们可以看知道这里完成了impl的初始化,然后创建了socket用于等待连接。
open : 创建socket_fd,创建descriptor_state,完成scoket_fd和descriptor的绑定以及向epoll监视集合中的注册。
bind: 绑定ip端口
listen :赋予socket监听能力
io_object_impl构造类
IoObjectService
为reactive_socket_service< tcp >
首先利用user_sevice()从传入的io_context的service_regitser获取reactive_socket_service< tcp >,如果没有则创建并添加到service_regitser中。然后调用reactive_socket_service<>基类方法初始化implemetation_,初始状态为无效状态。
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
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中。
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是asio最常用的函数之一,可以将普通函数任务添加到eventloop中。这部分流程不复杂,主要难点是模板相关的内容。下面为了尽可能详细,可能导致条理不是特别清晰,希望大家能给提点建议,帮助后续优化文章结构。
这里和上文一样,就是创建initiate_post对象,然后调用initiate_post的operator(),将handler,以及this指针作为传入参数。
代码大致上可以分为三部分
- 1部分以handler作为传入对象,创建非const属性的handler2
- 2部分根据handler类型实例化operation类型
- 3部分将该operation添加到eventloop的任务队列中。
下面对这三部分展开讲
上面拷贝构造函数中实际上就是对传入参数t进行了强制类型转换(如果T为引用,则强转为T的右值引用,否则强转为T的引用)
- 1为conditional主模板
- 2 为conditional模板类的偏特化模板
当我们实例化模板conditional时,如果 _Cond 是false,则匹配偏特化版本,则该condital类实例化类的type为第三个类型参数*** _Iffalse***;_Cond 非false,则匹配主模板,type为第二个类型参数*** _Iftrue***。
上面我们可以知道当我们用两个两个同样的类型实例化is_same时,is_same匹配ture_type;其他情况匹配false_type
ture_type,false_type 为使用如下类型参数实例化 integral_constant模板的typedef。
这段代码考察了非类型模板参数
第一个方框:类型参数_Tp
第二个方框 : 实例化时需要填入一个_Tp的值
所以上文false_type::value 为false。
用于退化类型,如T 为int&,我们std::decay< int& >::type 得到类型int。
详细介绍看下面链接
std::decay链接
完整代码如下
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_;
};
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::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
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);
}
};
上文可见调用如下 detail::associated_allocator_impl
可见第一个类型参数为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为利用模板实现的一个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流程。
Handler为std::bind返回的可调度对象,无内置allocator类型和excutor_type。
- associated_allocator_type 为std::allocator< void >
- hook_allocator_type 为 hook_allocator
- BOOST_ASIO_REBIND_ALLOC(hook_allocator_type, op)创建hook_allocator
::rebind::hook_allocator ,U为 completion_handler 的对象a。 - 调用a.allocate()即可获得completion_handler大小的内存。
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中。
上文已经将包裹函数对象handler的operation添加到了eventloop中。eventloop处理operation,调用completion_handler.do_complete方法。
构造completion_handler时,我们同时初始化了成员handler_work
右值引用
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);
}
}
对该模板还有部分没有搞清楚如何走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
//主模板
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);
}
};
在这里我们可以暂时得出结论:如可调度对象没有定义executor_type类型的话,complete_handler::do_complete 始终调用boost_asio_handler_invoke_helpers::invoke(function, handler),即立刻调用用户传入回调。