我想避免并行代码中的竞争条件.问题是我的类包含几个全局变量,让我们说一个x简单的变量,以及一个for我希望并行的循环.实际的代码还有一个方法,它接受一个类的指针,在本例中为自身,作为参数,访问更多的全局变量.因此,threadprivate.使用OpenMP 创建整个实例可能是有意义的.MWE是
#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();
}
Run Code Online (Sandbox Code Playgroud)
我的问题是,我该怎么做?使用该关键字threadprivate返回以下编译器错误消息:
error: ‘production’ declared ‘threadprivate’ after first use
我认为这里的编译器问题仍然没有解决:
这让我们知道为什么我使用英特尔编译器.Visual Studio 2013以及g ++(我的计算机上的4.6.2,Coliru(g ++ v5.2),编码地(g ++ v4.9.2))仅允许POD类型(源).这被列为近十年的错误,但仍未完全解决.给出的Visual Studio错误是错误C3057:'globalClass':当前不支持'threadprivate'符号的动态初始化,g ++给出的错误是错误:'globalClass'在首次使用后声明'threadprivate'英特尔编译器使用类.
不幸的是,我没有访问英特尔的编译器但使用GCC 8.1.0.我做了一些背景研究,并在这里找到了一个讨论,但十年前这条路很冷.我问这个问题是因为有几个人遇到过这个问题并通过在这里声明一个类指针或提出可怕的解决方法来解决它.后一种方法似乎是错误的,因为指针通常被声明为常量,但是threadprivate当实例仍然被共享时我们有指针.
我相信我可以使用private关键字,但我不确定如何使用整个类的实例执行此操作,尽管我更喜欢threadprivate关键字.我在上面对我的MWE建模的一个类似的例子也在本书的第7章,图7.17中进行了讨论,但是没有解决方案.(我很清楚竞争状况以及为什么会出现问题.)
如果有必要,我可以证明上述程序的输出没有任何额外的关键词是不确定的.
我现在想到了一个解决方案但由于某种原因,它不会编译.从线程安全和逻辑的角度来看,我的问题应该通过以下代码解决.然而,必定存在某种错误.
#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();
}
Run Code Online (Sandbox Code Playgroud)
所以这个代码,基于定义,应该做的伎俩,但不知何故它不编译.有人可以帮助我将这些代码放在一起,以便它实现所需的线程安全和编译,尊重threadprivate不是非英特尔编译器人员的选择的约束吗?非常感谢您的帮助.
这是 GCC 长期缺失的功能:
不过,在当前的 GCC 版本中,thread_local预计可以工作:
int main() {
thread_local lotswork production(0);
production.carryout();
}
Run Code Online (Sandbox Code Playgroud)
但是,我认为这不适用于您的情况,因为并行循环carryout仍将在单个lotswork实例上运行。我相信这也适用于使用的原始代码threadprivate。您可能需要将并行循环移到carryout成员函数之外。