我想避免并行代码中的竞争条件。问题是我的类包含几个全局变量,为了简单起见,我们只说一个 x
以及一个我希望并行的 for
循环。实际代码还有一个方法,它接受一个指向类的指针,在本例中是它本身,作为它的参数,访问更多的全局变量。因此,将整个实例设为 threadprivate 可能是有意义的。
我正在使用 OpenMP。
一个最小的工作示例是:
#include <iostream>
#include <omp.h>
class lotswork {
public:
int x;
int f[10];
lotswork(int i = 0) { x = i; };
void addInt(int y) { x = x + y; }
void carryout(){
#pragma omp parallel for
for (int n = 0; n < 10; ++n) {
this->addInt(n);
f[n] = x;
}
for(int j=0;j<10;++j){
std::cout << " array at " << j << " = " << f[j] << std::endl;
}
std::cout << "End result = " << x << std::endl;
}
};
int main() {
lotswork production(0);
#pragma omp threadprivate(production)
production.carryout();
}
我的问题是,我该怎么做?使用关键字 threadprivate
返回以下编译器错误消息:
错误:“production”在第一次使用后声明为“threadprivate”
我认为这里的编译器问题还没有 solved :
This brings us to why I used the Intel compiler. Visual Studio 2013 as well as g++ (4.6.2 on my computer, Coliru (g++ v5.2), codingground (g++ v4.9.2)) allow only POD types (source). This is listed as a bug for almost a decade and still hasn't been fully addressed. The Visual Studio error given is error C3057: 'globalClass' : dynamic initialization of 'threadprivate' symbols is not currently supported and the error given by g++ is error: 'globalClass' declared 'threadprivate' after first use The Intel compiler works with classes.
不幸的是,我无法访问英特尔的编译器,但使用的是 GCC 8.1.0。我做了一些背景研究并找到了关于这个的讨论 here ,但那条路在十年前就变冷了。我问这个问题是因为有几个人对此有疑问并通过将类指针声明为 here 来解决它。或提出糟糕的建议workarounds .后一种方法似乎被误导了,因为指针通常被声明为常量,但是当实例仍然共享时我们有 threadprivate
指针。
尝试解决
我相信我可以使用 private
关键字,但不确定如何对类的整个实例执行此操作,尽管我更喜欢 threadprivate
关键字。与上面我的 MWE 建模类似的示例也在第 7 章的图 7.17 中进行了讨论 this book , 但没有解。 (我很清楚竞争条件以及它为什么会成为问题。)
如有必要,我可以提供证据证明没有任何额外关键字的上述程序的输出是不确定的。
解决方案的另一种尝试
我现在想到了一个解决方案,但由于某种原因,它无法编译。从线程安全和逻辑的角度来看,我的问题应该通过以下代码解决。然而,一定有某种错误。
#include <iostream>
#include <omp.h>
class lotswork : public baseclass {
public:
int x;
int f[10];
lotswork(int i = 0) { x = i; };
void addInt(int y) { x = x + y; }
void carryout(){
//idea is to declare the instance private
#pragma omp parallel firstprivate(*this){
//here, another instance of the base class will be instantiated which is inside the parallel region and hence automatically private
baseclass<lotswork> solver;
#pragma omp for
for (int n = 0; n < 10; ++n)
{
this->addInt(n);
f[n] = x;
solver.minimize(*this,someothervariablethatisprivate);
}
} //closing the pragma omp parallel region
for(int j=0;j<10;++j){
std::cout << " array at " << j << " = " << f[j] << std::endl;
}
std::cout << "End result = " << x << std::endl;
}
};
int main() {
lotswork production(0);
#pragma omp threadprivate(production)
production.carryout();
}
因此,根据定义,这段代码应该可以解决问题,但不知何故无法编译。我如何将这段代码放在一起,以实现所需的线程安全和编译,同时考虑到 threadprivate 不是非英特尔编译器人员的选项的约束?
最佳答案
这是一个长期缺失的 GCC 功能:
对于当前的 GCC 版本,thread_local
应该可以工作,但是:
int main() {
thread_local lotswork production(0);
production.carryout();
}
但是,我认为这对您的情况不起作用,因为 carryout
中的并行循环仍将在单个 lotswork
实例上运行。我相信这也适用于使用 threadprivate
的原始代码。您可能需要将并行循环移到 carryout
成员函数之外。
关于c++ - 声明自身 (*this) 私有(private)的类以避免竞争条件/放弃 gcc 中线程私有(private)的请求,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54014391/