Boost.Asio 是 C++ 网络/异步编程的经典库(现在也是 C++26 标准网络库 std::net 的蓝本),确实是后台开发、C++ 中间件岗位面试的高频考点。下面按"核心概念→常考问题→常见坑"整理一下。
一、核心概念(必须吃透)
1. io_context(事件循环核心)
- 本质是一个任务调度器/事件分发器,负责执行所有异步操作的完成回调
run()/run_one()/poll()/poll_one()的区别:run()阻塞直到没有任务;poll()不阻塞,只处理当前就绪的任务- 没有任务时
run()会立即返回------这也是为什么常需要executor_work_guard(或旧版io_context::work)来"占住"事件循环,防止提前退出
2. Proactor 模式(Asio 的设计核心)
- 区别于 Reactor 模式:Reactor 是"事件就绪后你自己去读/写",Proactor 是"你发起异步操作,操作完成后系统通知你结果"
- 在 Windows 上 Asio 直接用 IOCP 实现真正的 Proactor;在 Linux 上底层是 epoll(Reactor),但 Asio 在上层模拟出 Proactor 语义------这个"模拟"过程是常问的深挖点
3. 异步操作模型
async_read/async_write/async_connect/async_accept等,配合 completion handler(回调)- Handler 的签名、错误码
error_code的传递方式(Asio 倾向用error_code而非异常)
4. Strand
- 用于保证一组 handler 不会并发执行(即便你用多线程
io_context::run()),从而避免手动加锁 - 常考:"多线程跑
io_context::run()时如何保证共享资源安全" → 答案就是 strand
5. Buffer 管理
mutable_buffer/const_buffer/streambuf,以及为什么异步操作时 buffer 的生命周期必须由调用者保证(这是最容易挖的坑)
6. 协程支持
- 早期的 stackful 协程(
asio::spawn) - C++20
co_await+asio::awaitable,这是现在业界更常用、面试也更常问的写法,因为能把异步代码写成"看起来同步"的形式,避免回调地狱
7. 定时器
steady_timer/deadline_timer,async_wait的用法,以及取消定时器的语义
二、面试高频问题
- Reactor vs Proactor 的区别,Asio 在 Linux 上如何用 epoll 模拟 Proactor
- 为什么需要 strand?不用会有什么问题?
- 一个异步 TCP echo server 怎么写(这是最常见的手写代码题)
- 对象生命周期问题:异步操作还没完成,对象就析构了怎么办?(标准答案:用
shared_ptr+enable_shared_from_this,在回调里shared_from_this()延长生命周期) io_context单线程 vs 多线程模型的优劣,线程池模式怎么实现- 协程版本和回调版本的对比,为什么协程更受欢迎
- 如何取消一个正在进行的异步操作
三、常见坑(写代码题时容易翻车的点)
- Buffer 悬空:异步操作发起后立刻用局部变量做 buffer,函数返回后 buffer 已析构
- 忘记 work guard :
io_context没活干直接退出,回调根本没机会执行 - 忘记 strand 导致 race condition:多线程下多个 handler 同时改共享状态
- 对象生命周期 :
this指针在异步回调触发时已经失效
要不要准备?
如果面试的岗位涉及 C++ 后端、网络编程、中间件(比如高性能网关、RPC 框架、游戏服务器),基本必考,至少要能:
- 讲清楚 Proactor 模式和异步模型的原理
- 手写一个简单的异步 echo server(TCP)
- 讲清楚 strand 和对象生命周期管理这两个"资深"信号点
如果岗位偏业务/客户端,问到的概率低一些,但了解基本概念(io_context、async/await 模型)通常还是加分项。
可以针对某一块(比如 async echo server 的手写代码、或者协程写法 vs 回调写法的对比)