文章目录
一、概述
Boost.Asio是一个用于网络和底层I/O编程的跨平台的C++库,它使用了现代的C++方法,为开发人员提供了一致的异步模型。使用前须知。
要使用Asio库,只需要代码中包含头文件:#include <boost/asio.hpp>
,Boost.Asio依赖如下的库:
- Boost.System:这个库为Boost库提供操作系统支持(http://www.boost.org/doc/libs/1_51_0/doc/html/boost_system/index.html)
- Boost.Regex:使用这个库(可选的)以便你重载
read_until()
或者async_read_until()
时使用boost::regex
参数。 - Boost.DateTime:使用这个库(可选的)以便你使用Boost.Asio中的计时器。
- OpenSSL:使用这个库(可选的)以便你使用Boost.Asio提供的SSL支持。
二、boost::asio::io_context
(1)io_context类为异步I/O对象提供核心功能,对象包括:
boost::asio::ip::tcp::socket
boost::asio::ip::tcp::acceptor
boost::asio::ip::udp::socket
boost::asio::deadline_timer
(2)提交任务请求函数
通过以下函数向io_context提交任务请求(官方建议不要使用io_context自带的成员函数defer()
、dispatch()
和post()
,因为它们即将被移除),其中参数handler
可以是函数对象,也可以是lambda
表达式:
boost::asio::defer(io_context, handler);
boost::asio::dispatch(io_context, handler);
向io_context请求执行handler
并立即返回,io_context保证handler
只会在run()
、poll()
接口执行的线程中被调用,dispatch()
接口内部不会调用handler
(但是如果run()
、poll()
接口执行是在当前线程执行,则dispatch()
内部会调用handler
)。boost::asio::post(io_context, handler);
向io_context请求执行handler
并立即返回,io_context保证handler
只会在run()
、poll()
接口执行的线程中被调用,post()
接口内部不会调用handler
。
(3)任务处理函数
count_type run();
1、执行事件循环,程序将被阻塞到任务被完成且再没有其他任务,或者直到io_context调用stop()
停止为止。
2、多线程中可以调用run()
来开启一个线程池,io_context可以在线程池中执行handler
。线程池中等待的所有线程都是等效的,io_context可以选择其中的任何一个线程来调用handler
。
3、在run()
正常退出后立即调用run()
、poll()
将会立即返回,除非在调用这些函数前调用restart()
。
4、函数将返回被处理的handler
数量。std::size_t run_for(const chrono::duration<Rep, Period>& rel_time);
在一定时间内处理事件循环,阻塞到任务被完成且没用其他任务,或者直到io_context调用stop()
停止,或者超时为止。参数rel_time
表示时间段。std::size_t run_until(const chrono::time_point<Clock, Duration>& abs_time);
在一定时间内处理事件循环,阻塞到任务被完成且没用其他任务,或者直到io_context调用stop()
停止,或者到达某个时间点为止。参数abs_time
表示阻塞到某个时间点。count_type run_one();
std::size_t run_one_for(const chrono::duration<Rep, Period>& rel_time);
std::size_t run_one_until(const chrono::time_point<Clock, Duration>& abs_time);
最多处理一个任务, 处理完就退出,或者io_context被停止。count_type poll();
以非阻塞方式执行事件循环,处理已就绪的任务,当没有其他已就绪的任务或者io_context被停止时返回。count_type poll_one();
以非阻塞方式处理任务,最多处理一个。
(4)其他函数
void stop();
停止事件处理循环,非阻塞,只是向io_context发出停止信号。调用该函数后,再调用run()
、poll()
将会立即返回,不会处理任任何handler
,直到调用restart()
。bool stopped() const;
用于判断io_context当前是否已停止,当已停止时,调用run()
、poll()
将立即返回,不会处理任任何handler
。void restart();
重新启动io_context,为后续调用run()
、poll()
做准备。
三、boost::asio::executor_work_guard、boost::asio::io_context::work
io_context在执行run()
后,如果没有I/O事件将会退出事件循环。但更多时候,我们希望run()
函数的事件循环在没有I/O事件的情况下,也不会退出事件循环,而是一直等待,当有了新的异步I/O调用的时候,还可以继续使用该循环。
(1)方法1
executor_work_guard的构造和析构分别调用了executor_.on_work_started();
和executor_.on_work_finished();
。
executor_
是executor_work_guard绑定的io_context对象,而on_work_started
才是真正保证即使io_context中没有任务的时候,run()
也不退出的关键。所以可以通过操控executor_work_guard生命周期的方法,来控制run()
什么时候退出。示例:
boost::asio::io_context ctx;
boost::asio::executor_work_guard<asio::io_context::executor_type> worker = boost::asio::make_work_gurad(ctx);
std::thread th([&ctx]() {
ctx.run();
});
...
worker.reset(); /* 允许run()退出 */
(2)方法2
work类的核心就是防止io_context在没有I/O事件的时退出。直接使用boost::asio::io_context::work(boost::asio::io_context& io_context);
的方式进行构造,当work对象被销毁时,它的作用就自动停止了。示例:
boost::asio::io_context ctx;
boost::asio::io_context::work worker(ctx);
std::thread th([&ctx]() {
ctx.run();
});
ctx.stop(); /* 先显式停止io_context, 否则无法终止 */
th.join();
四、boost::asio::detail::thread_group
线程池,可以预先创建指定线程个数,没有detach()
接口。示例:
boost::asio::io_context ctx;
boost::asio::io_context::work worker(ctx);
boost::asio::detail::thread_group threadPool;
threadPool.create_threads([&] {
ctx.run();
}, 16); /* 创建16个线程 */
threadPool.join();