gpt4 book ai didi

c++ - OpenMP导致heisenbug segfault

转载 作者:行者123 更新时间:2023-11-28 08:03:50 26 4
gpt4 key购买 nike

我正在尝试在OpenMP中并行化相当大的for-loop。大约有20%的时间运行正常,但其余时间会因各种段错误而崩溃,例如:

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

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

[2] <PID> segmentation fault ./execute


我的一般代码结构如下:

<declare and initialize shared variables here>
#pragma omp parallel private(list of private variables which are initialized in for loop) shared(much shorter list of shared variables)
{
#pragma omp for
for (index = 0 ; index < end ; index++) {

// Lots of functionality (science!)
// Calls to other deep functions which manipulate private variables
// Finally generated some calculated_values

shared_array1[index] = calculated_value1;
shared_array2[index] = calculated_value2;
shared_array3[index] = calculated_value3;

} // end for
}

// final tidy up


}

就发生的事情而言,每个循环迭代完全独立于其他循环迭代,除了它们从共享矩阵中提取数据(但每个循环迭代中的列不同)这一事实之外。在我调用其他函数的地方,它们只是在更改私有变量(尽管偶尔会读取共享变量),所以我认为它们是线程安全的,因为它们只会弄乱特定线程本地的内容?唯一写入所有共享变量的操作都在最后发生,我们将各种计算所得的值写入某些共享数组,其中数组元素由for循环索引进行索引。该代码使用C ++,尽管它调用的代码既是C语言又是C ++代码。

我一直在尝试找出问题的根源,但到目前为止还没有运气。如果我设置num_theads(1),它将运行良好,就像将 for-loop的内容括在一个单行中一样

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


大概会产生相同的效果(即在任何一次只能有一个线程可以通过循环)。

另一方面,如果我将 for-loop's内容包含在两个 critical指令中,例如

#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
}

}


我得到了无法预测的段错误。同样,如果我将每个函数调用都包含在 critical指令中,则仍然无法正常工作。

我认为该问题可能与函数调用有关,是因为当我使用 Valgrind(使用 valgrind --tool=drd --check-stack-var=yes --read-var-info=yes ./execute)以及SIGSEGing进行配置时,会出现疯狂的加载和存储错误,例如;

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


根据 the valgrind manual,这正是您对比赛条件的期望。当然,这种奇怪的出现/消失的问题似乎与比赛条件会带来的不确定性错误相一致,但我不明白,如果每个给出明显比赛条件的电话都在关键部分。

可能是错误的但我不认为的事情包括:


所有private()变量都在 for-loops内部初始化(因为它们是线程本地的)。
我检查了共享变量具有相同的内存地址,而私有变量具有不同的内存地址。
我不确定同步是否会有所帮助,但是鉴于在 barrier指令的入口和出口处存在隐式的 critical指令,并且我尝试了我的代码版本,其中每个函数调用都包含在(唯一命名)关键部分中我认为我们可以排除这一点。


对于如何最好地进行任何想法将不胜感激。我整天都在撞我的头。显然,我不是在寻找“哦-这是问题”类型的答案,而是更多有关如何在调试/解构方面进行的最佳方法。

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


代码中有一些std :: Vectors,它们利用vector.pushback()函数添加元素。我记得曾经读过,调整向量的大小不是线程安全的,但是向量只是私有变量,因此不会在线程之间共享。我想这可以吗?
如果我将整个 for-loop主体包含在 critical指令中,然后慢慢缩小代码块的末尾(因此 for-loop末尾的不断增长的区域在关键部分之外),则可以正常运行,直到暴露出函数调用之一,此时将继续执行段错误。使用Valgrind分析此二进制文件可显示许多其他函数调用中的竞争条件,而不仅仅是我公开的函数。
函数调用之一是GSL函数,根据Valgrind,它不会触发任何竞争条件。
我需要去在被调用的函数中明确定义私有变量和共享变量吗?如果是这样,这似乎对OpenMP有所限制-难道这不意味着您需要对所调用的任何旧代码都具有OpenMP兼容性吗?
并行化一个大 for-loop只是行不通吗?
如果您已经阅读了此书,请多谢Godspeed。

最佳答案

因此,没有任何人可以回答这个问题,但是弄清楚了这一点,我希望这对某人有帮助,因为我的系统的行为是如此奇怪。

我最终调用的(C)函数之一(my_function-> intermediate_function-> lower_function-> BAD_FUNCTION)将其多个变量声明为static,这意味着它们保留了相同的内存地址,因此本质上充当一个共享变量。有趣的是,静态优先于OpenMP。

我发现了这一切;


使用Valgrid识别错误发生的地方,并查看所涉及的特定变量。
将整个for-loop定义为关键部分,然后在顶部和底部暴露更多代码。
和我老板说话。更多的眼睛总是有帮助的,尤其是因为您被迫用语言表达问题(最终我打开了罪魁祸首功能并指向声明)

关于c++ - OpenMP导致heisenbug segfault,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/10729732/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com