C++ OpenMP导致海森堡故障

C++ OpenMP导致海森堡故障,c++,c,openmp,C++,C,Openmp,我正在尝试在OpenMP中并行化相当大的for循环。大约20%的时间它运行良好,但其余时间它崩溃与各种故障,如 *** glibc detected *** ./execute: double free or corruption (!prev): <address> *** *** glibc detected *** ./execute: free(): invalid next size (fast): <address> *** [2] <PID>

我正在尝试在OpenMP中并行化相当大的
for循环。大约20%的时间它运行良好,但其余时间它崩溃与各种故障,如

*** glibc detected *** ./execute: double free or corruption (!prev): <address> ***

*** glibc detected *** ./execute: free(): invalid next size (fast): <address> ***

[2] <PID> segmentation fault ./execute
这可能会产生相同的效果(即,在任何时间只有一个线程可以通过循环)

另一方面,如果我将
for循环的
内容包含在两个
关键
指令中,例如

#pragma omp for
for(index = 0 ; index < end ; index++) { 
  #pragma omp critical(whole_loop)
  { 
      // first half of loop body
  }

 #pragma omp critical(whole_loop2)
  { 
      // second half of loop body
  }

}
这正是你在比赛条件下所期望的。当然,这种奇怪的出现/消失的问题似乎与竞争条件会产生的非确定性错误是一致的,但我不明白,如果给出明显竞争条件的每个调用都在关键部分,会发生什么

可能出错的事情,但我不认为包括

  • 所有private()变量都在循环的
    中初始化(因为它们是线程本地的)

  • 我检查了共享变量是否具有相同的内存地址,而私有变量是否具有不同的内存地址

  • 我不确定同步是否有帮助,但考虑到进入和退出
    临界
    指令时存在隐式
    障碍
    指令,我已经尝试过我的代码版本,其中每个函数调用都包含在一个(唯一命名的)临界部分中,我想我们可以排除这种情况

如果您有任何关于如何最好地进行的想法,我们将不胜感激。我一整天都在为此绞尽脑汁。很明显,我不是在寻找一个“哦,问题出在这里”类型的答案,而是在调试/解构方面如何最好地继续

可能成为问题或可能有帮助的事情

  • 代码中有一些std::vector使用vector.pushback()函数添加元素。我记得读到过这样一篇文章:调整向量的大小不是线程安全的,但是向量只是私有变量,所以不能在线程之间共享。我想这样可以吗

  • 如果我将整个
    for循环
    主体包含在
    critical
    指令中,然后慢慢收缩代码块的末端(因此
    for循环
    末端不断增长的区域在临界部分之外),它将正常运行,直到我公开函数调用中的一个,此时分段故障恢复。用Valgrind分析这个二进制文件可以显示许多其他函数调用中的竞争条件,而不仅仅是我公开的那个

  • 其中一个函数调用是GSL函数,根据Valgrind,GSL函数不会触发任何竞争条件

  • 我是否需要在被调用的函数中明确定义私有和共享变量?如果是这样,这似乎对OpenMP有一定的限制-这是否意味着您需要对您调用的任何遗留代码具有OpenMP兼容性

  • 并行化一个大的
    for循环
    难道不管用吗

  • 如果你已经读到这里,谢谢你,祝你好运


因此,任何人都不可能回答这个问题,但我想知道了这一点,我希望这对某些人有所帮助,因为我的系统行为非常怪异

我最终调用的一个(C)函数(
myu函数
->
中间函数
->
下函数
->
坏函数
)将它的许多变量声明为
静态
,这意味着它们保留了相同的内存地址,因此本质上充当了一个共享变量。有趣的是,静态覆盖OpenMP

这一切都是我自己发现的

  • 使用Valgrid识别错误发生的位置,并查看所涉及的特定变量

  • 将整个
    for循环定义为关键部分,然后在顶部和底部公开更多代码

  • 和我的老板谈话。多看几眼总是有帮助的,尤其是因为你不得不把问题说出来(结果我打开了罪魁祸首函数并指向声明)


什么类型的共享阵列?计算值是什么类型的?共享数组是一个双精度数组,计算值也是这样(它们在生成时存储在本地的双精度私有向量中)我没有看到任何调用
malloc
free
,这是导致堆损坏的关键…如果在两个独立的关键部分中出现SEGFULTS,那么它们可能是相互依赖的。是否有些私有变量真的共享内部缓冲区?我的几个函数alloc和malloc创建和销毁数据结构,然后由其他函数操作。我在英特尔软件论坛上找到了一个非常可怕的建议,即在函数调用中从并行区域创建的变量必须是自动的并且在堆栈上(我的许多人不是这样)。有没有人有这方面的经验?这是真的吗?
静态
不会覆盖OpenMP-这是预期的行为。OpenMP标准(当前版本3.0)对静态变量非常清楚:在第2.9.1.1节中:“在构造内的作用域中声明的静态变量是共享的。”;在第2.9.1.2节:“在区域中调用的例程中声明的静态变量是共享的。”对不起,我应该明确指出,我并不是说这是一个bug,或者说这确实是出乎意料的。这只是(愚蠢地)出乎我的意料——我想你可以配置OpenMP,为每个线程在不同的内存位置创建
静态
变量。然而,你生活和学习(特别是,通过文档检查-感谢您的参考!)
#pragma omp for
for(index = 0 ; index < end ; index++) { 
  #pragma omp critical(whole_loop)
  { 
      // loop body
  }
}
#pragma omp for
for(index = 0 ; index < end ; index++) { 
  #pragma omp critical(whole_loop)
  { 
      // first half of loop body
  }

 #pragma omp critical(whole_loop2)
  { 
      // second half of loop body
  }

}
Conflicting load by thread 2 at <address> size <number>
   at <address> : function which is ultimately called from within my for loop