为何std::sleep_for(std::chrono::hours::max())在Linux上立即返回?
std::sleep_for(std::chrono::hours::max()) 在RHEL 8(gcc 8.5.0)中立即返回导致CPU占用100%
我在运行C++服务程序时碰到了一个诡异问题:无请求处理的空闲状态下,CPU占用率直接拉满到100%。排查后发现问题出在用来维持服务运行的while循环里——循环里调用std::sleep_for(std::chrono::hours::max())试图让程序休眠,结果这个sleep根本没起到挂起作用。
为了验证问题,我写了一段极简测试代码:
#include <chrono> #include <thread> int main(int argc, char * argv[]) { std::this_thread::sleep_for(std::chrono::hours::max()); }
按预期程序应该进入超长休眠,但在M1 Mac(用Apple clang编译)上表现正常,在Redhat Linux 8物理机和Mac上运行的Rocky Linux 8 Docker容器里,程序却直接立即退出。这说明这个问题在RHEL 8系统(至少搭配gcc 8.5.0时)是普遍存在的。
这也直接解释了服务CPU跑满的原因:原本指望sleep挂起线程,结果sleep立即返回,while循环变成了空转,疯狂占用CPU资源。我之前从没遇到过这种情况,想知道有没有其他人碰到过。(PS:我已经用std::chrono::seconds(1)替换解决了问题,纯粹是出于求知欲才提问)
问题根源
这是gcc 8.x版本libstdc++的一个已知问题,核心原因是时间值溢出:
- Linux下
std::sleep_for最终会调用内核的nanosleep系统调用,这个调用接收的struct timespec结构体中,tv_sec字段是time_t类型(多数32位系统为32位整数,部分旧版64位系统实现也存在处理漏洞)。 std::chrono::hours::max()的数值约为2.1e9小时,转换成秒是约7.7e11秒,远超过32位time_t的最大值(约1.3e9秒,对应大概42年)。这个超大值转换时会溢出,变成负数或者极小的正数,nanosleep会判定超时时间已到,直接返回。
而较新的gcc版本(比如gcc 9及以上)或者clang的libc++实现,已经修复了这个问题:会把超出time_t范围的时间值截断到最大值,让sleep能正常生效。
替代方案
除了改用小间隔休眠(比如每秒一次),也可以手动计算time_t的最大值,把休眠时间限制在这个范围内,避免溢出问题。
内容的提问来源于stack exchange,提问作者sonofagun
相关产品推荐
相关产品推荐

