C++ atomics学习中:race condition为何会出现x输出2,1的情况
2,1输出的产生原理
首先要明确:代码里的非原子++x根本不是不可拆分的原子操作,硬件层面会被拆成3个可被任意打断的独立步骤:
- 从全局内存加载x的当前值到当前线程绑定的CPU寄存器
- 在寄存器中对加载到的值做+1计算
- 把寄存器中的计算结果写回全局内存的x位置
这些步骤的任何间隙,操作系统调度器都可以暂停当前线程、切换CPU运行权;加上多CPU核心的缓存存在延迟,写回内存的操作可以拖很久执行,甚至直接覆盖其他线程已经写好的内存值。
触发2,1输出的完整时序链路:
- 初始全局x=0,t1启动执行add:把x=0加载到自己的寄存器,完成+1计算得到结果1,短暂把这个1写回内存让x变成1,随后立刻被调度器挂起,连cout的入口都没走到。此时t1的本地缓存还保留着自增的临时值状态。
- 调度器切到t2运行add:t2从内存读到当前x=1,走完完整自增流程,计算得到2并写回内存,此时全局x=2。随后t2执行cout逻辑,打印自己的线程名、当前内存中的x值2——这就是观测到的第一个输出值2。
- 之前被挂起的t1被调度回来:因为t1的本地缓存没有收到x已经被修改成2的失效通知,直接把自己缓存中保存的旧自增值1写回内存,把已经是2的全局x覆盖回1。之后t1才进入cout环节,从内存读到现在的x=1,将这个值打印出来——这就是观测到的第二个输出值1。
整个过程没有任何程序错误,只是无同步的非原子变量在多线程下的正常竞态表现,只要存在数据竞争,所有理论上可能的时序组合都有概率被观测到。
内容的提问来源于stack exchange,提问作者Emulato 679
相关产品推荐
相关产品推荐

