核心名词
- io_context:事件循环/调度器,负责等待事件并执行回调(handler)。统一管理 IO 与定时器回调,便于扩展到网络模型。
- handler(回调) :事件就绪后被
run()调用的函数/lambda。 - async_wait:登记一次"到期后执行 handler"的异步操作;调用后立即返回(不阻塞)。
- steady_timer:稳定定时器(不受系统时间调整影响)。
- 多线程 run :多个线程同时调用
ioc.run(),同一时刻可能执行多个 handler。 - strand :保证绑定到同一 strand 的 handler 不并发执行(串行化),但不保证固定线程。
- work_guard :防止
run()在暂时无任务时提前返回;reset()后允许自然退出。
封装业务对象:Ticker
cpp
class Ticker : public std::enable_shared_from_this<Ticker> {
public:
Ticker(asio::io_context &ico, int limit, std::function<void()> on_done)
: strand_(asio::make_strand(ico)), timer_(strand_), limit_(limit),
on_done_(on_done) {}
void start() {
// 开始第一次的tick
schedule_next_tick();
}
private:
void schedule_next_tick() {
timer_.expires_after(1s);
timer_.async_wait(
[self = shared_from_this()](const boost::system::error_code &ec) {
if (ec) {
std::cerr << "timer async wait error: " << ec.message() << "\n";
return;
}
self->tick();
});
}
void tick() {
++count_;
std::cout << "tick: " << count_
<< " (thread_id=" << std::this_thread::get_id() << ")\n";
if (count_ >= limit_) {
if (on_done_)
on_done_();
return;
}
// 安排下一次tick
schedule_next_tick();
}
private:
asio::strand<asio::any_io_executor> strand_;
asio::steady_timer timer_;
int count_ = 0;
int limit_;
std::function<void()> on_done_;
};
- Ticker集成
[std::](std::enable_shared_from_this,回调里面捕获shared_from_this()。
为什么这样做?
- 异步回调可能在未来任意时刻触发
- 捕获
shared_ptr可以保证回调执行时对象仍然存在,避免悬空指针
- 内部绑定
strand_绑定定时器调用- 多线程运行
io_context会导致回调并发执行 strand保证同一对象的回调串行化,避免数据竞争- 这样
count_不需要加锁,更容易推理行为。
- 多线程运行
thread pool
strand (serial executor)
handler A
handler B
handler C
thread1: ioc.run()
thread2: ioc.run()
thread3: ioc.run()
io_context
ready handlers queue
schedule_next_tick()里expires_after(1s)+async_wait,回调中再调用schedule_next_tick()- 把"下一次调度"放在回调里,避免阻塞线程
- 更容易与
io_context的事件循环协作
保持事件循环存活(work_guard)
cpp
auto guard = asio::make_work_guard(ico);
auto on_done = [&guard]() { guard.reset(); };
- 创建
executor_work_guard,任务完成后reset()- 若没有未完成异步任务,
io_context.run()会立即返回 work_guard让事件循环持续运行,直到我们主动停止- 完成时
reset(),确保线程池可以自然退出
- 若没有未完成异步任务,
线程池启动
cpp
// 线程池
std::vector<std::thread> pool;
pool.reserve(threads);
for (int i = 0; i < threads; ++i) {
pool.emplace_back([&ico]() {
ico.run();
});
}
for (auto &t : pool) {
t.join();
}
线程与并发模型
- 线程池数量由
threads控制 io_context可以被多个线程并发运行- 绑定
strand_的回调串行执行,避免数据竞争
最小代码骨架
cpp
asio::io_context ioc;
auto guard = asio::make_work_guard(ioc); // 可选但常用
// 1) 创建异步对象(timer/socket等)
// 2) 发起 async_* 操作,提供 handler(回调)
start_async_ops();
// 3) 一个或多个线程跑事件循环
std::thread t([&]{ ioc.run(); });
t.join();
定时器循环的通用写法:
cpp
void schedule() {
timer.expires_after(1s);
timer.async_wait([this](ec){
if (!ec) { do_work(); schedule(); }
});
}