本文基于Boost 1.69,在展现源代码时删减了部分deprecated或者不一样配置的与本文主题无关的代码块。react
这里以围绕reactor提供服务的reative_socket_service
为例,介绍一下service。windows
// file: <boost/asio/detail/reactive_socket_service.hpp> ... template <typename Protocol> class reactive_socket_service : public service_base<reactive_socket_service<Protocol> >, public reactive_socket_service_base ...
reative_socket_service
继承了service_base<reactive_socket_service<Protocol>>
,前文已经介绍了,service_base
包含一个静态成员id
。因为子类是父类模版的参数(Curiously Recurring Template Pattern),因此每个继承了service_base
的类包含一个不一样的静态成员id
。这个id
能够用于注册服务。服务器
// file: <boost/asio/io_context.hpp> ... template <typename Type> class service_base : public boost::asio::io_context::service { public: static boost::asio::detail::service_id<Type> id; // Constructor. service_base(boost::asio::io_context& io_context) : boost::asio::io_context::service(io_context){} }; ...
reative_socket_service
继承了reactive_socket_service_base
,这个父类已经实现了至关多的功能。reactive_socket_service_base
成员为io_context
引用、reactor
引用。其核心成员函数为reactive_socket_service_base::start_op
,将具体的impl
(native socket handle及其状态、native socket handle相关的reactor数据)、op
(操做)传递给reactor
。值得注意的是,若是noop
为真,代表这是一个通常性操做,reactor会将任务提交给scheduler来完成。关于op、handler等概念,本文后面会进行讲解。异步
// file: <boost/asio/detail/impl/reactive_socket_service_base.ipp> ... void reactive_socket_service_base::start_op( reactive_socket_service_base::base_implementation_type& impl, int op_type, reactor_op* op, bool is_continuation, bool is_non_blocking, bool noop) { if (!noop) { if ((impl.state_ & socket_ops::non_blocking) || socket_ops::set_internal_non_blocking( impl.socket_, impl.state_, true, op->ec_)) { reactor_.start_op(op_type, impl.socket_, impl.reactor_data_, op, is_continuation, is_non_blocking); return; } } reactor_.post_immediate_completion(op, is_continuation); } ...
介绍了reactive_socket_service_base::start_op
,咱们再来看一个与socket io操做相关的成员函数reactive_socket_service_base::async_send
。async_send
成员函数自己很简单,其参数主要是socket(impl
)、数据(buffers
)和回调(handler
),经过将任意类型的handler
包装成reactive_socket_send_op
而后经过调用start_op
把任务传递给reactor
。start_op
成员函数最后一个参数为noop
,当socket(impl
)为stream_oriented且buffers是empty时(即noop
=true),任务会直接交给scheduler
。socket
// file: <boost/asio/detail/impl/reactive_socket_service_base.ipp> ... // Start an asynchronous send. The data being sent must be valid for the // lifetime of the asynchronous operation. template <typename ConstBufferSequence, typename Handler> void async_send(base_implementation_type& impl, const ConstBufferSequence& buffers, socket_base::message_flags flags, Handler& handler) { bool is_continuation = boost_asio_handler_cont_helpers::is_continuation(handler); // Allocate and construct an operation to wrap the handler. typedef reactive_socket_send_op<ConstBufferSequence, Handler> op; typename op::ptr p = { boost::asio::detail::addressof(handler), op::ptr::allocate(handler), 0 }; p.p = new (p.v) op(impl.socket_, impl.state_, buffers, flags, handler); BOOST_ASIO_HANDLER_CREATION((reactor_.context(), *p.p, "socket", &impl, impl.socket_, "async_send")); start_op(impl, reactor::write_op, p.p, is_continuation, true, ((impl.state_ & socket_ops::stream_oriented) && buffer_sequence_adapter<boost::asio::const_buffer, ConstBufferSequence>::all_empty(buffers))); p.v = p.p = 0; } ...
做为Boost.Asio的用户,若是要实现异步的tcp服务器的话,离不开相应的boost::asio::ip::tcp::socket
(即basic_stream_socket<tcp>
),这里就以此来介绍service的使用。查看源代码可知,basic_stream_socket
继承了basic_socket
,basic_socket
继承了basic_io_object
。其中BOOST_ASIO_SVC_T
为服务的类型,在windows之外平台被定义为detail::reactive_socket_service<Protocol>
。async
// file: <boost/asio/basic_stream_socket.hpp> ... template <typename Protocol BOOST_ASIO_SVC_TPARAM_DEF1(= stream_socket_service<Protocol>)> class basic_stream_socket : public basic_socket<Protocol BOOST_ASIO_SVC_TARG> ... // file: <boost/asio/basic_socket.hpp> ... #if !defined(BOOST_ASIO_ENABLE_OLD_SERVICES) # if defined(BOOST_ASIO_WINDOWS_RUNTIME) # include <boost/asio/detail/winrt_ssocket_service.hpp> # define BOOST_ASIO_SVC_T detail::winrt_ssocket_service<Protocol> # elif defined(BOOST_ASIO_HAS_IOCP) # include <boost/asio/detail/win_iocp_socket_service.hpp> # define BOOST_ASIO_SVC_T detail::win_iocp_socket_service<Protocol> # else # include <boost/asio/detail/reactive_socket_service.hpp> # define BOOST_ASIO_SVC_T detail::reactive_socket_service<Protocol> # endif #endif // !defined(BOOST_ASIO_ENABLE_OLD_SERVICES) ... template <typename Protocol BOOST_ASIO_SVC_TPARAM> class basic_socket : BOOST_ASIO_SVC_ACCESS basic_io_object<BOOST_ASIO_SVC_T>, public socket_base ...
查看basic_io_object
的源代码可知,basic_io_object
包含两个成员:service_
和implementation_
,其中implementation_
包含socket native handle及相关状态和handle相关的reactor数据, service_
经过boost::asio::use_service<IoObjectService>(io_context)
函数构建,use_service
查询io_context
的服务队列来返回对应的服务,若是队列中没有相应的服务,io_context
会构建一个新的服务。tcp
// file: <boost/asio/basic_io_object.hpp> ... #if !defined(BOOST_ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION) template <typename IoObjectService> #else template <typename IoObjectService, bool Movable = detail::service_has_move<IoObjectService>::value> #endif class basic_io_object { public: /// The type of the service that will be used to provide I/O operations. typedef IoObjectService service_type; /// The underlying implementation type of I/O object. typedef typename service_type::implementation_type implementation_type; ... protected: ... explicit basic_io_object(boost::asio::io_context& io_context) : service_(boost::asio::use_service<IoObjectService>(io_context)) { service_.construct(implementation_); } ... /// Get the service associated with the I/O object. service_type& get_service() { return service_; } ... /// Get the underlying implementation of the I/O object. implementation_type& get_implementation() { return implementation_; } ... private: ... // The service associated with the I/O object. service_type& service_; /// The underlying implementation of the I/O object. implementation_type implementation_; }; ...
以上,咱们得知了boost::asio::ip::tcp::socket
如何获取服务,下面再来看看如何使用服务。以boost::asio::ip::tcp::socket
的async_send
为例,查看源代码可知,async_send
调用service的相关async成员函数,并传入implementation、数据及回调便可。handler自己的处理稍后讲解。ide
// file: <boost/asio/basic_stream_socket.hpp> ... template <typename ConstBufferSequence, typename WriteHandler> BOOST_ASIO_INITFN_RESULT_TYPE(WriteHandler, void (boost::system::error_code, std::size_t)) async_send(const ConstBufferSequence& buffers, socket_base::message_flags flags, BOOST_ASIO_MOVE_ARG(WriteHandler) handler) { // If you get an error on the following line it means that your handler does // not meet the documented type requirements for a WriteHandler. BOOST_ASIO_WRITE_HANDLER_CHECK(WriteHandler, handler) type_check; ... async_completion<WriteHandler, void (boost::system::error_code, std::size_t)> init(handler); this->get_service().async_send( this->get_implementation(), buffers, flags, init.completion_handler); return init.result.get(); ... } ...
对于异步io来讲,用户没法直接等待io完成后进行后续的操做,这类“操做”须要保存起来,在io到达某个特定状态后由库自动调用。对于这一过程,我将简略介绍相关概念,Asio实现,并列出一些文献供读者深刻理解与学习。函数
Boost.Asio 引入了一个统一的异步模型,文章 N3747. A Universal Model for Asynchronous Operations 详细讲解了其中涉及的各种异步操做和统一模型的概念。从文章 N3747 看出,C++的异步操做包含的类型有callbacks、future、resumable functions及协程。因为篇幅有限,本文再也不复述文章 N3747 中的概念性内容,而着重于经过分析Asio源代码来介绍这一模型的具体实现。oop
下面首先以Asio内部的角度(scheduler操做队列,reactor操做队列等)来了解异步操做在Asio中如何实现。查看源码可知,scheduler
操做队列的实际类型为op_queue<scheduler_operation>
,而io_context
生成任务并传递给scheduler
的类型是detail::executor_op<function_type, Allocator, detail::operation>
,所以咱们首先关注两个类:scheduler_operation
和executor_op
。scheduler_operation
是一个普通的类,而executor_op
是一个类模版并默认继承scheduler_operation
(这里继承关系很重要)。这两个类的结合产生了有趣的做用,其中
scheduler_operation
:回调接口,类型擦除executor_op
:类模版,负责产生多样性,并将多样性传递给父类scheduler_operation
具体来讲,executor_op
包含一个静态成员函数do_complete
,将base
(void *
)cast为executor_op *
在进行相关操做,而scheduler_operation
有一个类型为函数指针的数据成员func_
。executor_op
构建时将静态成员函数do_complete
的地址赋值给scheduler_operation
的数据成员func_
函数指针,scheduler_operation
执行completion的时候会调用这个函数将自身this
还原(cast)为实例化的executor_op *
。经过子类模版和子类静态方法,父类和父类数据成员函数指针,实现了类型擦除与重现的功能。
scheduler_operation
和executor_op
,生命周期管理。父类scheduler_operation
的成员函数complete
销毁对象并完成回调(调用func_(owner,...)
),destroy
仅仅销毁对象(调用func_(0,...)
),而父类的析构函数并非虚函数且函数体为空。查看executor_op
的静态成员函数do_complete
,其生命管理过程以下:
o
(类型为executor_op*
)的allocator
o
生命周期的ptr
类实例p
,注意p
的析构函数会自动销毁o
(若是o
在这以前未被销毁的话)。o
的数据成员handler_
移动到一个本地变量,p.reset()
销毁o
owner
的值决定是否调用handler_
// file: <boost/asio/detail/executor_op.hpp> ... template <typename Handler, typename Alloc, typename Operation = scheduler_operation> class executor_op : public Operation { public: BOOST_ASIO_DEFINE_HANDLER_ALLOCATOR_PTR(executor_op); template <typename H> executor_op(BOOST_ASIO_MOVE_ARG(H) h, const Alloc& allocator) : Operation(&executor_op::do_complete), handler_(BOOST_ASIO_MOVE_CAST(H)(h)), allocator_(allocator) { } 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. executor_op* o(static_cast<executor_op*>(base)); Alloc allocator(o->allocator_); ptr p = { detail::addressof(allocator), o, o }; ... Handler handler(BOOST_ASIO_MOVE_CAST(Handler)(o->handler_)); p.reset(); // Make the upcall if required. if (owner) { ... } } private: Handler handler_; Alloc allocator_; }; ... // file: <boost/asio/detail/scheduler_operation.hpp> ... class scheduler_operation BOOST_ASIO_INHERIT_TRACKED_HANDLER { public: typedef scheduler_operation operation_type; void complete(void* owner, const boost::system::error_code& ec, std::size_t bytes_transferred) { func_(owner, this, ec, bytes_transferred); } void destroy() { func_(0, this, boost::system::error_code(), 0); } protected: typedef void (*func_type)(void*, scheduler_operation*, const boost::system::error_code&, std::size_t); scheduler_operation(func_type func) : next_(0), func_(func), task_result_(0) { } // Prevents deletion through this type. ~scheduler_operation() { } private: friend class op_queue_access; scheduler_operation* next_; func_type func_; protected: friend class scheduler; unsigned int task_result_; // Passed into bytes transferred. };
前面咱们经过介绍executor_op
已经大体了解了Asio核心部分组装异步操做的方法,其余的op例如reactor_op
及其子类的实现与executor_op
基本相似,这里再也不额外进行说明。剩下的部分是异步操做的用户接口和统一模型。
一个典型的接口是boost::asio::post
函数,该函数将异步操做(任意类型)提交给指定的io_context异步运行。为了实现统一模型,函数必须决定返回值和异步操做的真正类型:返回值,若是用户提交的是通常的callback,则返回值应为空,若是是future这种方式的异步操做,则必须返回相应的对象;异步操做的真正类型转换,对于callback来讲,类型是functor,对于协程则是相应的placeholder,Asio必须将用户提交的参数转换为真正的异步操做类型。
经过查看boost::asio::post
的函数体,咱们发现:
async_result_helper
被用来决定boost::asio::post
返回值的类型async_completion
在函数体内进行异步类型转换,生成返回值阅读async_completion
的源代码发现,async_completion
类包含数据成员completion_handler
和result
,而这两个成员的类型由async_result
类模版(traits)肯定(result
的类型也是async_result
)。默认状况下,async_result
返回值类型为空,真正的异步操做类型直接等于用户提交的异步操做类(boost::asio::post
函数模版的形参CompletionToken
)。async_result
在默认状况下没有任何数据成员,这样async_completion
的数据成员result
做为异步操做的返回值(类型为async_result
)能够被编译器优化,对于普通的不须要返回值的callback来讲避免了额外的开销。
为了处理future类型的异步操做(须要返回值和真正的异步操做类型),经过定义async_result
关于future的特化便可。
// file: <boost/asio/impl/post.hpp> ... template <typename Executor, typename CompletionToken> BOOST_ASIO_INITFN_RESULT_TYPE(CompletionToken, void()) post( const Executor& ex, BOOST_ASIO_MOVE_ARG(CompletionToken) token, typename enable_if<is_executor<Executor>::value>::type*) { typedef BOOST_ASIO_HANDLER_TYPE(CompletionToken, void()) handler; async_completion<CompletionToken, void()> init(token); typename associated_allocator<handler>::type alloc( (get_associated_allocator)(init.completion_handler)); ex.post(detail::work_dispatcher<handler>(init.completion_handler), alloc); return init.result.get(); } ... // file: <boost/asio/async_result.hpp> ... template <typename CompletionToken, typename Signature> struct async_completion { /// The real handler type to be used for the asynchronous operation. typedef typename boost::asio::async_result< typename decay<CompletionToken>::type, Signature>::completion_handler_type completion_handler_type; ... /// Constructor. /** * The constructor creates the concrete completion handler and makes the link * between the handler and the asynchronous result. */ explicit async_completion(CompletionToken& token) : completion_handler(static_cast<typename conditional< is_same<CompletionToken, completion_handler_type>::value, completion_handler_type&, CompletionToken&&>::type>(token)), result(completion_handler) { } ... /// A copy of, or reference to, a real handler object. typename conditional< is_same<CompletionToken, completion_handler_type>::value, completion_handler_type&, completion_handler_type>::type completion_handler; ... /// The result of the asynchronous operation's initiating function. async_result<typename decay<CompletionToken>::type, Signature> result; }; ... template <typename CompletionToken, typename Signature> class async_result { public: ... /// The concrete completion handler type for the specific signature. typedef CompletionToken completion_handler_type; ... /// The return type of the initiating function. typedef void return_type; ... /// Construct an async result from a given handler. /** * When using a specalised async_result, the constructor has an opportunity * to initialise some state associated with the completion handler, which is * then returned from the initiating function. */ explicit async_result(completion_handler_type& h) #if defined(BOOST_ASIO_NO_DEPRECATED) || defined(GENERATING_DOCUMENTATION) // No data members to initialise. { (void)h; } ... /// Obtain the value to be returned from the initiating function. return_type get() { ... // Nothing to do. ... } // No data members. }; ...