C++本身不内置事件循环,但可通过标准库、第三方库(如libuv)或手动构建实现;核心包括事件队列、I/O多路复用(epoll/kqueue)和任务调度;支持协程、多线程协同及跨平台应用。

C++ 本身不内置事件循环(Event Loop),但可以通过标准库、第三方库或手动构建实现一个轻量或生产级的事件循环模型。核心思路是:维护一个事件队列 + 一个可轮询/等待的 I/O 多路复用机制(如 epoll/kqueue/select)+ 任务调度逻辑。
基础事件循环结构(无外部依赖)
一个最小可行的事件循环包含三部分:事件队列(存储待处理的回调)、I/O 监听器(检测文件描述符就绪)、主循环(取事件、执行、等待)。适合学习原理或嵌入式/游戏等简单场景。
- 使用 std::queue<:function>> 存储定时任务和普通回调
- 用 std::vector
或自定义结构管理监听的 fd(Linux 下可配合 epoll_wait) - 主循环调用
epoll_wait等待就绪事件,同时检查队列中是否有立即执行的任务或到期的定时器 - 注意避免“饥饿”:需限制单次循环中执行的回调数量,或按时间片分配执行时长
基于 libuv 的跨平台事件循环(推荐实践)
libuv 是 Node.js 使用的 C 库,提供成熟、稳定、跨平台的事件循环抽象,C++ 可直接封装调用。它已内置定时器、异步文件 I/O、子进程、TCP/UDP、信号处理等能力。
- 初始化
uv_loop_t*,启动后自动运行uv_run(loop, UV_RUN_DEFAULT) - 通过
uv_timer_t、uv_async_t、uv_poll_t等句柄注册事件回调 - C++ 封装建议:用 RAII 包装句柄(如 Timer 类析构时自动关闭),避免裸指针管理
- 注意线程安全:libuv 默认单线程循环,跨线程触发需用
uv_async_send,不可直接从其他线程调用回调
现代 C++ 协程 + 事件循环(C++20 趋势)
结合 std::coroutine 和自定义 awaiter,可写出类似 async/await 的异步代码,底层仍依赖事件循环驱动。
立即学习“C++免费学习笔记(深入)”;
- 设计一个
Task类型,其 awaiter 在挂起时将协程句柄加入事件队列,就绪后恢复 - I/O 操作(如 socket read)封装为
awaitable,内部调用epoll_ctl注册读就绪事件,并把协程挂起 - 关键点:事件循环需识别协程状态,在 fd 就绪时调用
resume();需管理协程栈生命周期(通常堆分配) - 已有实践参考:Boost.Asio 以 C++20 协程支持重构了 async 接口;cppcoro 库也提供了 event loop 基础设施
与多线程模型的协同(非阻塞 + 线程池)
纯事件循环适合高并发 I/O,但 CPU 密集型任务会阻塞循环。常见解法是分层:事件循环负责 I/O 调度,重负载任务投递到线程池,结果再通过 async 或管道通知回主循环。
- 主线程运行事件循环(如 libuv loop),工作线程运行
std::thread+std::queue任务队列 - 线程池完成计算后,用
uv_async_send(libuv)或eventfd(Linux)唤醒主循环,触发回调处理结果 - 避免锁竞争:任务提交和结果通知尽量无锁(如 ring buffer + 原子计数器),或仅在队列操作时加轻量互斥锁
- 典型组合:libuv(事件) + thread_pool(CPU) + lock-free queue(通信)











