VS2017 Community中OpenMP代码疑似Bug的技术问询
OpenMP并行代码异常问题分析
环境信息
- 操作系统:Windows 10(SDK 10.0.18362.0)
- 编译器:VS2017 Community 版本15.9.34,工具集v141
测试代码
#include <iostream> int main() { bool isFirst = true; #pragma omp parallel shared(isFirst) { int values[35]; #pragma omp for schedule(dynamic) for (int i = 0; i < 4; i++) { #pragma omp critical { if (isFirst) { isFirst = false; std::cout << i << std::endl; } std::fill_n(values, 35, 3); } } } }
现象与临时修复
预期共享变量isFirst仅为true一次,程序仅输出一个数值,但实际输出多个无序值(如3、2、0、1)。临时修复方法包括:
- 修改
std::cout的输出内容 - 将
bool isFirst = true;改为bool isFirst[1] = {true};并使用isFirst[0] - 移除
std::fill_n(values, 35, 3);语句
问题解答
1. 是本人疏漏还是Visual Studio的Bug?
这是Visual Studio 2017 v141工具集的编译器Bug,和代码逻辑无关。
代码本身符合OpenMP规范:通过critical区域保证对共享变量isFirst的互斥访问,理论上只有第一个进入临界区的线程会将isFirst设为false并输出数值。但编译器优化时,对栈上的isFirst变量做了错误的缓存处理——即便标记为shared,编译器也没正确同步临界区内的修改,导致多个线程读取到的isFirst仍为true。
临时修复的逻辑也能印证这一点:
- 改用数组
isFirst[1]时,变量存储区域的特性让编译器不会过度缓存,线程能正确读取修改后的值; - 移除
std::fill_n或修改cout输出,会改变编译器的优化策略,规避了错误的缓存行为。
2. 能否复现该Bug?
可以复现。在指定的VS2017环境下多次运行代码,大概率会出现多输出的情况;开启编译器优化(如O2等级)后,复现概率会更高。
3. 该问题是否出现在其他VS版本或编译器中?
- 后续VS版本:VS2019及更高版本(对应v142及以上工具集)已修复此问题,运行相同代码只会输出一个数值,符合预期。
- 其他编译器:GCC、Clang等支持OpenMP的主流编译器,运行该代码均能得到预期结果,不会出现多输出情况,说明这是MSVC v141工具集特有的优化Bug。
内容的提问来源于stack exchange,提问作者nbonneel
相关产品推荐
相关产品推荐

