派生自std::jthread的类中线程访问成员变量的合法性疑问
你的顾虑完全正确,这段代码存在未定义行为
你的代码确实存在未定义行为,虽然测试中总能输出42,但这不代表它具备通用有效性——线程完全有可能在my_int完成构造与初始化前就尝试读取它。
核心原因:C++对象构造顺序与线程启动时机
- 构造顺序规则:派生类对象的构造流程是「先构造基类部分,再按成员变量的声明顺序初始化成员」。你的
MyThread继承自std::jthread,所以在MyThread的构造过程中,会先完成std::jthread基类的构造,之后才会初始化my_int成员。 - 线程启动时机:根据C++标准,
std::jthread对象构造完成后,关联的线程会立即开始执行。也就是说,你传入的lambda在std::jthread基类构造完成的瞬间就可能启动运行,而此时my_int还没完成=42的初始化操作。
lambda中通过this访问my_int时,读取的是一个尚未完成构造的原子变量,这属于标准明确规定的未定义行为。测试中能输出42只是巧合——线程启动后的执行可能存在微小延迟,刚好让my_int赶在读取前完成初始化,但这种依赖时机的行为在不同编译器、平台或运行场景下完全不可靠,随时可能出现错误结果。
修复思路
要避免这种问题,必须保证线程启动时,所有需要访问的成员都已完成初始化:
- 不要在基类构造阶段启动线程访问派生类成员,可以在
MyThread构造完成后再启动线程(比如提供一个专门的启动方法); - 将
my_int的值作为参数传递给线程函数,而非通过this访问; - 或者使用同步机制,让线程等待
my_int初始化完成后再执行读取操作。
内容的提问来源于stack exchange,提问作者bers
相关产品推荐
相关产品推荐

