是,std::thread启动大量线程会崩溃;因系统线程数和栈内存受限,linux易触发“resource temporarily unavailable”,windows报“too many open files”,须改用线程池或事件驱动模型。

std::thread 启动大量线程会直接崩溃?
超过几千个 std::thread 实例时,程序大概率在 Linux 上触发 Resource temporarily unavailable(errno=11),Windows 上则可能抛出 std::system_error(code=24,too many open files)。这不是代码写错了,是系统级限制:每个线程默认占 2MB 栈空间 + 一个内核线程对象,还消耗进程的文件描述符(用于线程间同步)。
实操建议:
- 别用
std::thread一一对应请求;改用线程池 + 任务队列,典型如std::queue配合std::mutex+std::condition_variable - Linux 下可通过
ulimit -s查看栈大小,ulimit -n查看文件描述符上限;启动前加ulimit -n 65535只能缓解,不能根治 - 若必须高并发(>10k 连接),优先考虑
epoll(Linux)或iocp(Windows)+ 单线程事件循环,而非多线程阻塞 socket
std::chrono::steady_clock 做压测计时为什么不准?
用 std::chrono::high_resolution_clock 或错误地用 system_clock 测单次请求耗时,会在高负载下出现跳变甚至负值——因为前者不保证单调,后者受系统时间调整影响。压测要求的是稳定、单调、低开销的时间源。
实操建议:
- 只用
std::chrono::steady_clock,它基于单调递增的硬件计数器(如 TSC),不受 NTP 调整干扰 - 避免在循环内反复调用
now();对每批请求(如每 100 次)统一起始/结束时间戳,再除以数量,减少函数调用开销 - 注意:某些虚拟机(如 VirtualBox)下
steady_clock可能退化为system_clock,上线前需用std::chrono::steady_clock::is_steady断言校验
如何避免 std::shared_ptr 在高并发压测中成为性能瓶颈?
当每个请求都封装成 std::shared_ptr<request></request> 并在线程间传递时,operator++ 和 operator-- 的原子操作会引发缓存行争用(false sharing),尤其在 NUMA 架构上,QPS 可能骤降 30% 以上。
实操建议:
- 请求对象尽量栈分配或池化(
boost::object_pool或自定义 arena allocator),避免共享指针管理生命周期 - 若必须用
shared_ptr,确保其控制块(control block)分配在独立缓存行上;可用alignas(64)对齐自定义分配器 - 压测中禁用
std::make_shared的优化(它把对象和控制块连续分配),改用两段式构造:new对象 +shared_ptr构造函数传入原始指针
HTTP 请求发出去但 recv() 阻塞住?检查 SO_RCVTIMEO 和 TCP_NODELAY
压测客户端常卡在 recv(),表现为“请求已发,响应没回来”,实际是服务端未及时 FIN 或网络中间设备(如 NAT 网关)静默丢包。默认阻塞模式会让线程无限挂起。
实操建议:
- socket 创建后立即设置
SO_RCVTIMEO:用setsockopt(fd, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv)),tv设为 500ms 内合理超时 - 关闭 Nagle 算法:
setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &on, sizeof(on)),否则小包(如 HTTP HEAD)会被延迟合并,放大 P99 延迟 - 不要依赖
select()或poll()做单连接超时;它们无法感知 TCP 层重传超时,必须结合SO_RCVTIMEO
ss -i(Linux)查 rcv_space 和 retrans 字段,而不是只盯着自己的 std::thread::hardware_concurrency()。C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











