C++多线程计算PVZ种子 单线程正常多线程结果异常排查
问题定位
多线程运行异常的核心原因是appear函数存在严重的跨线程数据竞争,和原子变量res无关:
inline bool* appear(int uid, int mode, const string& scene, int level, int seed) { static bool havez[34]; // 致命错误点 memset(havez, 0, sizeof(havez)); // 后续所有对havez的读写操作 // ... return havez; }
函数内部用static修饰的局部变量存储在全局共享内存区,所有线程调用appear函数时都会操作同一块内存,没有任何同步保护:
- 某线程刚完成部分
havez数组的赋值,就会被其他线程执行的memset直接清零覆盖,导致僵尸存在性的判定结果完全随机,自然无法得到正确种子 - 加延时后不同线程操作
havez的时间窗口被错开,不会互相覆盖,所以程序能正常运行 - 调试时线程切换频繁,多个线程反复抢占修改同一块内存,绝大多数CPU时间都耗在无效的内存覆盖和错误计算上,所以表现为运行速度极慢但CPU占用率很高。
另外存在一个次要竞态点:calcThread中对res的空判断和赋值是两个独立操作,极端情况下会有多个线程同时通过判断写入res,虽然不影响找到正确结果,但存在极小概率返回非预期值。
修复方法
- 移除
appear函数中的静态共享数组,改为每个调用独立的内存空间,彻底杜绝跨线程共享:删除static bool havez[34];定义,改为函数内局部数组bool havez[34] = {false};;不要返回栈上局部数组的指针,直接把僵尸判定逻辑放到appear函数内部,返回当前种子是否符合要求的bool结果即可,从根源上避免共享内存和野指针问题。 - 优化
res的写入逻辑,将判断和赋值合并为原子操作:将原代码的if (!res)res = seed;替换为
保证只有第一个找到合法种子的线程能写入结果,完全消除竞态。int expected = 0; res.compare_exchange_strong(expected, seed);
修复后代码单线程、多线程运行都能稳定返回预期结果114452,计算性能可随CPU核心数线性提升。
内容的提问来源于stack exchange,提问作者Kndy996
相关产品推荐
相关产品推荐

