C++使用std::thread多线程执行自增操作大数值下输出异常原因问询
问题原因解析
1. 对join()的功能误解
join()的作用不是让你创建的t1、t2按顺序串行执行,它仅仅是让调用join()的主线程在当前位置阻塞,等待目标子线程执行完毕后再继续向下运行。
你在创建t1、t2的那一刻,两个子线程就已经被操作系统调度开始并行执行,并不是等调用join()时才启动,也不会等t1执行完t2才开始运行,join()完全不会干预子线程之间的执行时序。
2. 结果不稳定的根本原因:竞态条件
你遇到的结果不符合预期是典型的多线程竞态条件问题,和join()是否生效没有任何关系:
- 你写的
m++看起来是一行代码,实际在CPU执行时会被拆分为3步:读取内存中m的当前值到寄存器、寄存器值+1、将新值写回内存 - 没有同步保护的情况下,两个线程可能同时执行这3步操作,比如线程1读取到m=100、加1为101还没写回时,线程2也读取到m=100、加1为101,最终两个线程都写回101,本该两次自增得到102,实际只加了1,最终结果就会小于预期的
2*var - 小数值
var下结果符合预期的原因是:任务执行时间极短,可能t1在t2被操作系统调度启动前就已经执行完所有操作,两个线程的执行时间没有重叠,刚好没有触发冲突,属于巧合的正确,不是必然结果。
3. volatile的作用误区
这里你用到的volatile完全无法解决多线程同步问题,它的作用仅仅是告诉编译器不要对该变量的读写做指令优化,每次都必须直接从内存读取、直接写回内存,既不保证操作的原子性,也不提供多线程所需的内存屏障,对线程安全没有任何帮助。
修复方案
- 方案一:将普通变量替换为原子变量,只需修改
m的定义即可,原子变量的自增操作原生是线程安全的:
std::atomic<int> m = 0;
- 方案二:使用互斥锁保护临界区,每次操作
m前加锁,操作完成后解锁:
volatile int m = 0; std::mutex mtx; void ThdFun(int i) { for (int j = 0; j < i; ++j) { std::lock_guard<std::mutex> lock(mtx); m++; } }
内容的提问来源于stack exchange,提问作者Megan Darcy
相关产品推荐
相关产品推荐

