OpenMP- private、firstprivate、lastprivate、shared、threadprivate、copyin、copyprivate
private
private用于指定变量在并行区域中的私有性。当一个变量声明为私有时,每个线程都会为该变量创建自己的私有拷贝,这样在并行执行过程中,每个线程都可以独立地访问和修改该变量,而不会影响其他线程的变量值。
firstprivate
firstprivate用于将变量声明为私有,并且每个线程在进入并行区域时,主线程都会将该变量初始化为并行区域外部作用域中的初始值。换句话说,firstprivate将会对变量进行私有化,并且将其初始化为并行区域外部的值。
firstprivate通常用于在并行区域中使用外部作用域中的变量的初始值,而不需要担心并行区域中的修改会影响到外部变量的值。
lastprivate
lastprivate 是 OpenMP 中的一个指令,用于指定循环结束时要保存的变量的值。它将循环的最终值从并行区域中的线程传递回主线程,以便主线程可以使用该值。
通常情况下,循环中的迭代变量在每个线程中都有自己的私有副本。但是当需要使用循环结束时的最终值时,可以使用 lastprivate 指令来将最后一个迭代的值传递回主线程。🙈
注:lastprivate子句指定了在并行区域结束后,私有变量的最终值应该由最后一个迭代的线程确定,并将其保留到并行区域之外。对于数组而言,lastprivate子句会将最后一个迭代中数组的所有元素的值复制到对应位置的全局数组中。
shared
shared 是 OpenMP 中的一个关键字,用于指定在并行区域中被所有线程共享的变量。在并行区域中,共享变量的值对于所有线程是可见的,并且所有线程可以读取和修改这些变量。
通常情况下,变量在并行区域内默认是共享的,但是为了代码的可读性和明确性,可以使用 shared 关键字明确地指定变量的共享性。
threadprivate
threadprivate用于在多线程环境中为每个线程创建私有变量。通常情况下,OpenMP中的变量默认是共享的,也就是说所有线程都可以访问同一个变量的同一份副本。然而,在某些情况下,需要为每个线程创建独立的变量副本,以避免并发访问问题。
threadprivate指令允许程序员将变量声明为线程私有,这意味着每个线程都会有该变量的一个私有拷贝。这样可以确保每个线程对变量的访问互不干扰,从而避免并发访问引起的问题。
如果需要在整个程序中,每个线程都有自己的全局变量副本,则可以使用 threadprivate。而如果只是在某个并行区域内部需要一个私有变量,那么应该使用 private。可以赋初始值。
#include <iostream>
#include <omp.h>
#define NUM_THREADS 10
using namespace std;
int k;
#pragma omp threadprivate(k)
int main(int argc, char* argv[]){
int x = 0, y = 2, s[5], v = 0;
// omp_set_num_threads(num_threads); 运行时动态设置线程数
#pragma omp parallel private(x) firstprivate(y) shared(v) num_threads(NUM_THREADS)
{
int id = omp_get_thread_num();
x = id;
y += id;
v += id;
k = id + 2;
cout << "thread " << id << ": x = " << x << "; y = " << y << "; k = " << k << endl;
}
cout << "main thread: x = " << x << "; y = " << y << "; v = " << v << endl;
#pragma omp parallel num_threads(6)
{
k = omp_get_thread_num();
cout << "thread-> " << k << endl;
}
#pragma omp parallel for lastprivate(s)
for (int i = 0; i < 5; ++i) {
s[i] = i + 1;
}
for (int i = 0; i < 5; ++i) {
cout << s[i] << " "; // 只有一个值是正确的
}
return 0;
}
copyin
copyin 子句提供了一种机制,可将主线程的线程私有变量值复制到执行并行区域的团队其他成员的线程私有变量中。
#include <iostream>
#include <omp.h>
using namespace std;
int var = 666;
#pragma omp threadprivate(var)
int main(int argc, char* argv[]){
#pragma omp parallel copyin(var)
{
int id = omp_get_thread_num();
#pragma omp master
{
var = 999;
cout << "[1]master thread " << id << ": var = " << var << endl;
}
#pragma omp barrier
cout << "[1]thread " << id << ": var = " << var << endl;
}
#pragma omp parallel copyin(var)
{
int id = omp_get_thread_num();
cout << "[2]thread " << id << ": var = " << var << endl;
}
return 0;
}
copyin
[1]master thread 0: var = 999
[1]thread 0: var = 999
[1]thread 2: var = 666
[1]thread 4: var = 666
[1]thread 1: var = 666
[1]thread 3: var = 666
[1]thread 7: var = 666
[1]thread 6: var = 666
[1]thread 5: var = 666
[2]thread 0: var = 999
[2]thread 2: var = 999
[2]thread 3: var = 999
[2]thread 7: var = 999
[2]thread 1: var = 999
[2]thread 4: var = 999
[2]thread 6: var = 999
[2]thread 5: var = 999
注:使用copyin前要先将变量声明为threadprivate类型的,且对于threadprivate,要求指定的变量具有静态存储期限(全局变量或静态局部变量),即在程序启动时分配并在程序结束时释放。copyin 变量可以不初始化且会被修改。
copyprivate
copyprivate 是一个可以在单个构造中使用的子句,它提供一种机制,将一个隐式任务中私有的变量值广播到该并行区域中其他隐式任务的值。
#include <iostream>
#include <omp.h>
using namespace std;
int main(int argc, char* argv[]){
int var = 111;
#pragma omp parallel firstprivate(var)
{
int id = omp_get_thread_num();
cout << "[before] thread " << id << ": var = " << var << endl;
#pragma omp barrier
#pragma omp single copyprivate(var)
{
var = 333;
cout << "[single] thread " << id << ": var = " << var << endl;
}
cout << "[after]thread " << id << ": var = " << var << endl;
}
return 0;
}
copyprivate
[before] thread [before] thread [before] thread 3: var = 111
0: var = 111
1: var = 111
[before] thread 2: var = 111
[single] thread 0: var = 333
[after]thread 0[after]thread : var = 1[after]thread 333
3: var = 333
: var = 333
[after]thread 2: var = 333
。。。

浙公网安备 33010602011771号