我在 OpenMP 中遇到了一个奇怪的错误。运行程序时,我收到 sigkill 或 sig abort。但有时程序也会成功。
sig Kill 或 sig abort 可能发生在多个地方。有时会出现超出范围的错误。
它看起来像是一场数据竞赛,但运行 valgrind --tool=helgrind 或 drd 不会带来很多信息。我怀疑运行 helgrind 时它甚至会崩溃。
预期结果:关键和有序都应该有效。应该只有速度差异。这是一些细节
1)只有在 Linux 中使用 gnu 编译时才会发生这种情况。在Windows下用MSVC编译的程序没有问题。 使用的命令是
g+= -o -std=c++17 -Wall -fopenmp -O2 -g -fno-var-tracking
2)这似乎是由于 omp 关键而发生的。当我用订购的 omp 替换它时,问题就消失了。
我可以获得 sigkill 或 sig abort 的地方似乎有所不同。所以我什至无法确定出了什么问题。
helgrind 报告了数据竞争,但它们是这样的
==2191== 线程 #1 在 0x837BF50 处写入大小 4 时可能出现数据争用 ==2191== 持有的锁:无 ==2191==位于0x5583F92:??? (在/usr/lib/x86_64-linux-gnu/libgomp.so.1.0.0中) ==2191== 0x55823A1:??? (在/usr/lib/x86_64-linux-gnu/libgomp.so.1.0.0中) ==2191== by 0x5578ED9:GOMP_parallel(在/usr/lib/x86_64-linux-gnu/libgomp.so.1.0.0中)
下面是我的代码的简化示例
calc(
vector<DataObj>& outputs,
vector<DataObj>& inputs,
)
{
omp_set_dynamic(0);
omp_set_nested(0);
int rc = 1;
int maxThreads = omp_get_max_threads();
const int nProperties = static_cast<int>(inputs.size());
#pragma omp parallel for schedule(static) \
shared(outputs,inputs,maxThreads) reduction(&:rc) \
num_threads(nProperties < maxThreads ? nProperties : maxThreads)
for (int projN = 0; projN < nProperties; ++projN)
{
DataObj* projectResults = &(outputs.at(projN));
Calculator* calculator = nullptr;
#pragma omp critical
{
calculator = new Calculator(inputs[projN]);
}
{
// resultHolder does most of its work in destructor, important to keep the braces for scope control
Allocator::Project resultsHolder(projectResults);
rc &= calculator->calc(
projectResults);
}
delete calculator;
}
return rc;
}
示例代码调整:
omp critical
来保护对共享资源的访问,或考虑使用 omp ordered
等替代方案或针对不同行为的其他同步机制。#pragma omp parallel for schedule(static) shared(outputs,inputs,maxThreads) reduction(&:rc) num_threads(nProperties < maxThreads ? nProperties : maxThreads)
for (int projN = 0; projN < nProperties; ++projN) {
DataObj* projectResults = &(outputs.at(projN));
Calculator* calculator = nullptr;
#pragma omp critical
{
calculator = new Calculator(inputs[projN]);
}
// Scope for resultHolder to ensure destructor is called before calculator deletion
{
Allocator::Project resultsHolder(projectResults);
rc &= calculator->calc(projectResults);
}
delete calculator;
}