接前一篇文章:C++常用容器、函数、类集(11)
本文内容参考:
https://juejin.cn/post/7386514632725430306
Boost.Asio _boost:asio::run-优快云博客
boost::asio::io_context, boost::asio::steady_timer定时器_boost asio context 弃用-优快云博客
特此致谢!
20. boost::asio::io_context
Boost.Asio是一个被广泛使用的库,它为网络通信、定时器、文件I/O等提供了统一的异步模型。而在这套模型的背后,有一个核心组件扮演着至关重要的角色 —— boost::asio::io_context。
(1)简介
boost::asio::io_context是Boost.Asio库中用于管理I/O执行上下文的核心类,负责调度和执行异步操作。io_context类是整个Asio库的中心,几乎所有的异步操作都需要通过它来执行。
功能和作用:
- 事件循环
io_context提供了一个事件循环(event loop),用于处理异步事件。当通过调用io_context的run()方法,启动io_context的运行时,它会开始监听和分发事件,如网络I/O事件、定时器事件等。
- 服务调度
io_context负责调度和分发异步操作的完成事件。当一个异步操作完成(例如,一个异步读取操作从socket完成)时,io_context负责调用与该操作相关联的处理程序(handler)。
- 资源管理
io_context还管理着一些底层资源,如socket和定时器等,确保这些资源的生命周期得到正确管理。
总之,你可以将io_context看作是异步任务的“调度中心”或“运行引擎”,所有的异步操作(如网络请求、定时器、异步读写等)都需要通过一个boost::asio::io_context实例来驱动。
(2)工作原理及使用流程
boost::asio::io_context类似于一个事件循环,负责管理和调度异步任务。典型的使用流程如下:
1)创建一个boost::asio::io_context实例;
2)将异步任务(如定时器、网络I/O操作等)绑定到io_context上;
3)调用io_context::run(),进入事件循环,开始处理异步任务。
(3)单线程与多线程环境中的行为表现
1)在单线程中的行为
在单线程环境中,io_context::run()会阻塞当前线程,直到所有绑定的任务都完成或被取消。
2)在多线程中的行为
在多线程环境中,io_context依然是单一的事件分发器,但多个线程可以同时调用io_context::run()方法。这种情况下,io_context会将异步任务分发给不同的线程来处理。
具体工作机制:
- 线程安全性
io_context本身是线程安全的。多个线程可以安全地调用io_context::run()、io_context::post()等方法。Boost.Asio内部使用了互斥锁和其它同步机制来确保线程安全。
- 任务分发
当有多个线程在运行io_context::run()时,io_context会将任务分发给第一个可用的线程。具体来说,当一个线程完成当前任务并准备处理下一个任务时,io_context会将一个新的任务分配给该线程。
- 负载均衡
通过这种机制,io_context能够实现一定程度的负载均衡,确保多个线程能够有效地并行处理任务。
(4)代码示例
1)示例1
以下是一个简单的示例,展示了如何在多线程环境中使用io_context:
#include <boost/asio.hpp>
#include <iostream>
#include <thread>
#include <vector>
void worker(boost::asio::io_context& io_context) {
io_context.run();
}
int main() {
boost::asio::io_context io_context;
// 创建一些工作线程
std::vector<std::thread> threads;
for (int i = 0; i < 4; ++i) {
threads.emplace_back(worker, std::ref(io_context));
}
// 在 io_context 上调度一些任务
io_context.post([]() { std::cout << "Task 1\n"; });
io_context.post([]() { std::cout << "Task 2\n"; });
io_context.post([]() { std::cout << "Task 3\n"; });
// 等待所有工作线程完成
for (auto& thread : threads) {
thread.join();
}
return 0;
}
在此示例中,首先创建了一个io_context实例;接着启动了4个工作线程来运行io_context;然后,在io_context上调度了几个任务,这些任务会被不同的线程并行处理。
2)示例2
以下是一个创建asio::steady_timer的例子。asio::steady_timer是一个与asio::io_context关联的定时器,可以用来在给定的时间点执行一个函数或者是在一个固定的时间间隔后执行一个函数。
#include <iostream>
#include <chrono>
#include <asio.hpp>
int main()
{
asio::io_context io_context;
asio::steady_timer timer(io_context, std::chrono::seconds(5));
timer.async_wait([](const asio::error_code& error)
{
if (!error)
{
std::cout << "Timer expired." << std::endl;
}
});
io_context.run();
return 0;
}
在此示例中,首先创建了一个asio::io_context;接着创建了一个asio::steady_timer,并设置了它在5秒后过期;然后注册了一个异步等待操作,并在定时器到期时会打印一条消息;最后,我们运行I/O执行环境。
(5)注意事项
- 避免竞争条件:尽管io_context本身是线程安全的,但你的任务代码可能不是。确保在多线程环境中访问共享资源时使用适当的同步机制(如互斥锁)。
- 线程数量:创建过多的线程可能会导致上下文切换开销增加,降低整体性能。根据具体的任务类型和系统硬件,选择适当的线程数量。
- 任务调度:如果所有任务都由一个线程处理,可能会导致其他线程空闲,无法充分利用多核 CPU 的性能。合理地分配和调度任务,确保多线程环境中的负载均衡。
(6)总结
boost::asio::io_context在多线程环境中提供了一种高效的异步任务调度机制。通过多个线程调用io_context::run(),可以实现任务的并行处理,从而充分利用多核CPU的性能。然而,在使用时需要注意避免竞争条件、合理选择线程数量和任务调度,以确保程序的稳定性和高效性。
更多内容请看下回。