假设我在对象中打包了一些资源,然后根据资源执行一些计算.我通常做的是初始化并行区域之外的对象,然后使用firstprivte关键字
int main()
{
// initialize Widget objs
Widget Widobj{params1,params2,params3...};
#pragma omp parallel for firstprivate(Widobj)
for (int i=0; i< N; ++i)
{
// computation based on resources in Widobj
}
}
我认为在这种情况下,每个线程将独立处理Widobj中的资源,我想每个线程都有一个Widobj的副本(可能是一个深层副本,我是对的吗?).现在我对其他关键字threadprivate感到困惑,threadprivate在这个上下文中如何工作?在我看来他们非常相似
解决方法:
当一个对象被声明为firstprivate时,将调用复制构造函数,而当使用private时,将调用默认构造函数.我们将在下面解决threadprivate.证明(英特尔C 15.0):
#include <iostream>
#include <omp.h>
class myclass {
int _n;
public:
myclass(int n) : _n(n) { std::cout << "int c'tor\n"; }
myclass() : _n(0) { std::cout << "def c'tor\n"; }
myclass(const myclass & other) : _n(other._n)
{ std::cout << "copy c'tor\n"; }
~myclass() { std::cout << "bye bye\n"; }
void print() { std::cout << _n << "\n"; }
void add(int t) { _n += t; }
};
myclass globalClass;
#pragma omp threadprivate (globalClass)
int main(int argc, char* argv[])
{
std::cout << "\nBegninning main()\n";
myclass inst(17);
std::cout << "\nEntering parallel region #0 (using firstprivate)\n";
#pragma omp parallel firstprivate(inst)
{
std::cout << "Hi\n";
}
std::cout << "\nEntering parallel region #1 (using private)\n";
#pragma omp parallel private(inst)
{
std::cout << "Hi\n";
}
std::cout << "\nEntering parallel region #2 (printing the value of "
"the global instance(s) and adding the thread number)\n";
#pragma omp parallel
{
globalClass.print();
globalClass.add(omp_get_thread_num());
}
std::cout << "\nEntering parallel region #3 (printing the global instance(s))\n";
#pragma omp parallel
{
globalClass.print();
}
std::cout << "\nAbout to leave main()\n";
return 0;
}
给
def c’tor
Begninning main()
int c’torEntering parallel region #0 (using firstprivate)
copy c’tor
Hi
bye bye
copy c’tor
Hi
bye bye
copy c’tor
Hi
bye bye
copy c’tor
Hi
bye byeEntering parallel region #1 (using private)
def c’tor
Hi
bye bye
def c’tor
Hi
bye bye
def c’tor
Hi
bye bye
def c’tor
Hi
bye byeEntering parallel region #2 (printing the value of the global instance(s) and adding the thread number)
def c’tor
0
def c’tor
0
def c’tor
0
0Entering parallel region #3 (printing the global instance(s))
0
1
2
3About to leave main()
bye bye
bye bye
如果复制构造函数执行深层复制(如果您必须编写自己的复制,并且默认情况下,如果您没有,并且具有动态分配的数据),那么您将获得对象的深层副本.这与不使用现有对象初始化私有副本的private相反.
threadprivate的工作方式完全不同.首先,它仅适用于全局或静态变量.更重要的是,它本身就是一个指令,并且不支持任何其他条款.你可以在某处编写threadprivate pragma行,然后在并行块之前编写#pragma omp parallel.还有其他差异(在内存中存储对象等),但这是一个良好的开端.
让我们分析一下上面的输出.
首先,请注意,在进入区域#2时,将调用默认构造函数,为线程创建一个私有的新全局变量.这是因为在进入第一个并行区域时,全局变量的并行副本尚不存在.
接下来,当NoseKnowsAll考虑最关键的区别时,线程私有全局变量通过不同的并行区域持久化.在区域#3中没有构造,我们看到保留了来自区域#2的添加的OMP线程号.还要注意,在区域2和3中没有调用析构函数,而是在离开main()之后(由于某种原因只有一个(主)副本 – 另一个是inst.这可能是一个错误……).
这让我们知道为什么我使用英特尔编译器. Visual Studio 2013以及g(我的计算机上的4.6.2,Coliru (g++ v5.2),codingground (g++ v4.9.2))仅允许POD类型(source).这被列为近十年的错误,但仍未完全解决.
给出的Visual Studio错误是
error C3057: ‘globalClass’ : dynamic initialization of ‘threadprivate’ symbols is not currently supported
并且g给出的误差是
error: ‘globalClass’ declared ‘threadprivate’ after first use
英特尔编译器适用于类.
再说一遍.如果要复制主线程变量的值,可以使用#pragma omp parallel copyin(globalVarName)
.请注意,这不适用于上面示例中的类(因此我将其删除).
资料来源:OMP tutorial:private,firstprivate,threadprivate
标签:c,openmp 来源: https://codeday.me/bug/20190929/1833857.html
本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享; 2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关; 3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关; 4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除; 5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。