std::promise<void>抛出未知错误,添加零时长sleep为何可规避?
为什么GCC 4.8/5.4中std::promise直接操作会抛异常,加0时长sleep就正常?
这个问题我刚好了解过,本质是早期GCC版本里libstdc++的一个和线程库初始化相关的小bug,咱们一步步拆解清楚:
问题重现
你给出的第一段代码在GCC 4.8.5和5.4.0下编译运行会抛出std::system_error:
#include <future> #include <thread> int main() { std::promise<void> p; p.set_value(); p.get_future().get(); return 0; }
编译运行命令:
$ g++ -o foo foo.cpp -std=c++11 -lpthread $ ./foo terminate called after throwing an instance of 'std::system_error' what(): Unknown error -1
而添加零时长sleep后,程序就能正常运行无异常:
int main() { std::this_thread::sleep_for(std::chrono::milliseconds(0)); std::promise<void> p; p.set_value(); p.get_future().get(); return 0; }
核心原因
这个现象的根源在于旧版本libstdc++中线程库的初始化时机问题:
std::promise和std::future的实现依赖pthread库的同步原语(比如互斥锁、条件变量)。- 主线程启动时,pthread库的初始化并不是完全同步完成的。当你在
main函数最开头直接操作std::promise时,pthread库的某些关键内部结构还没初始化好,导致底层同步调用失败,最终抛出std::system_error(错误码-1对应底层pthread调用返回的未初始化错误)。
为什么零时长sleep能解决问题?
std::this_thread::sleep_for哪怕是0毫秒的睡眠,其底层实现也会调用pthread的相关函数(比如pthread_cond_timedwait)。这些函数会触发pthread库的完整初始化流程,确保所有必要的内部结构都已准备就绪。等后续再创建std::promise并执行操作时,依赖的同步机制已经正常工作,自然就不会抛出异常了。
后续解决方案
这个bug在GCC 6及以上的版本中已经被彻底修复,如果你能升级到更高版本的GCC,就不需要再用这种临时的workaround了。如果必须使用旧版本,除了添加零时长sleep,也可以在程序开头手动触发线程库初始化(比如创建一个临时线程再销毁,或者调用pthread_once),效果是一样的。
内容的提问来源于stack exchange,提问作者Tomasz Maciejewski
相关产品推荐
相关产品推荐

