64位版本中STL/OpenMP的奇怪并发问题

Pet*_*ter 11 c++ 64-bit stl thread-safety visual-c++

当我在64位调试配置中构建我们的一个项目时,我有一个奇怪的问题.它似乎产生了一些奇怪的行为,看起来有点像单个迭代器多次递增.我把它缩小到以下测试代码:

#include <omp.h>

#define _HAS_ITERATOR_DEBUGGING 0

#include <vector>
#include <set>

int main(int argc, const char* argv[]) {    
   std::vector<int> v;
   for(int j = 0; j < 20; ++j) {
      v.push_back(j);
   }

   #pragma omp parallel for
   for(int i = 0; i < 100000; ++i) {
      std::set<int> s;
      std::vector<int>::const_iterator begin = v.begin(), end = v.end();
      s.insert(begin, end); // after this line s should contain the numbers 0-19
      if(s.size() != 20) {
         printf("fail\n");
         exit(3);
      }
   }
   return 0;
}
Run Code Online (Sandbox Code Playgroud)

但是,大小测试经常失败,这意味着它不会以某种方式插入向量的整个内容 - 并且对它进行大量的调整使得它看起来更像是向量迭代器一次增加多个步骤.这很难说,因为如果用调试器中断,它就不会发生.

绘制的明显结论是它不是线程安全的,但我的理解是它应该是因为唯一修改的变量是s具有局部范围的.

有很多东西可以解决眼前的问题:

  • 删除并行
  • 在insert()通话中抛出关键部分
  • #define HAS_ITERATOR_DEBUGGING 1
  • 用手动循环替换单个insert()调用并单独插入每个项目(这基本上是该函数在内部执行的操作,但是当我自己执行时问题肯定会消失)
  • 构建相同代码的32位版本
  • 构建相同代码的发布版本

这是在MSVC++ 2008 SP1下编译的,带有编译器提供的STL实现.

任何人都可以了解这里发生的事情吗?提前感谢任何提示 - 我很难过:)

编辑:如果不清楚,我不是在寻找一个"快速修复"来使这个代码工作; 如上所述,我知道其中很多.我想要了解的是为什么这个问题首先发生.

编辑2:使用gcc编译时代码正常工作.

Ale*_*nov 2

看起来像是 OpenMP 和/或 STL 的 VS 2008 实现中的一个错误。用VS 2010,就不复现了;而且它没有用 Intel 的编译器和 VS 2008 头文件重现,这让我认为这个 bug 更有可能出现在 VC++ 编译器的 OpenMP 支持中。

编辑:我之前发布的带有firstprivate的代码确实不起作用,即使_SECURE_SCL=1也是如此。看来我只是幸运地跑了一次。