局部变量应该对每个线程自动私有.如何将本地指针指向并行区域外的某个地址,例如
A * a = new A[10];
int i, j;
for (i = 0; i < 10; i++){
A * local_i = &a[i];
// do sth ...
#pragma omp parallel for
for (j = 0; j < 10; j++){
A * local_j = &a[j];
local_j->x = 1.0f;
// ...
}
}
delete[]a;
Run Code Online (Sandbox Code Playgroud)
我应该local_a私人和afisrtprivate吗?我实际上是OpenMP和C的新手.
重要的是要知道OpenMP以不同方式处理静态和动态数组.在示例中,您提供的静态数组更合适.让我们来看看在静态和动态数组上使用shared,private和firstprivate时会发生什么.我将为每种情况打印线程号,a的地址,a的值和数组的值.
静态数组:
int a[10];
for(int i=0; i<10; i++) a[i]=i;
#pragma omp parallel
{
#pragma omp critical
{
printf("ithread %d %p %p :", omp_get_thread_num(), &a, a); for(int i=0; i<10; i++) printf("%d ", a[i]); printf("\n");
}
}
//ithread 1 0x7fff3f43f9b0 0x7fff3f43f9b0 :0 1 2 3 4 5 6 7 8 9
//ithread 3 0x7fff3f43f9b0 0x7fff3f43f9b0 :0 1 2 3 4 5 6 7 8 9
Run Code Online (Sandbox Code Playgroud)
请注意,每个线程都具有相同的地址a.现在让我们尝试传递a私人.
#pragma omp parallel private(a)
//ithread 0 0x7fffc7897d60 0x7fffc7897d60 :4 0 -1393351936 2041147031 4 0 0 0 4196216 0
//ithread 1 0x7fa65f275df0 0x7fa65f275df0 :0 0 0 0 0 0 1612169760 32678 1596418496 32678
Run Code Online (Sandbox Code Playgroud)
现在每个线程都有它的私有a,每个私有版本都指向不同的内存地址.但是,它们的数组值未被复制.现在让我们试试吧firstprivate(a)
#pragma omp parallel firstprivate(a)
//ithread 0 0x7ffffb5ba860 0x7ffffb5ba860 :0 1 2 3 4 5 6 7 8 9
//ithread 3 0x7f50a8272df0 0x7f50a8272df0 :0 1 2 3 4 5 6 7 8 9
Run Code Online (Sandbox Code Playgroud)
现在唯一的区别a是复制了ARE 的值.
动态数组:
int *a = new int[10];
for(int i=0; i<10; i++) a[i]=i;
Run Code Online (Sandbox Code Playgroud)
让我们首先看一下a共享的传递
#pragma omp parallel
//ithread 2 0x7fff86a02cc8 0x9ff010 :0 1 2 3 4 5 6 7 8 9
//ithread 0 0x7fff86a02cc8 0x9ff010 :0 1 2 3 4 5 6 7 8 9
Run Code Online (Sandbox Code Playgroud)
每个线程都a像静态数组一样.当我们使用私有时,会发生差异.
#pragma omp parallel private(a)
//segmentation fault
Run Code Online (Sandbox Code Playgroud)
每个线程都有自己的私有a,就像静态数组一样,但每个版本指向的内存地址是未分配的随机内存.当我们尝试阅读它时,我们会遇到分段错误.我们可以解决这个问题firstprivate(a)
#pragma omp parallel firstprivate(a)
//ithread 0 0x7fff2baa2b48 0x8bd010 :0 1 2 3 4 5 6 7 8 9
//ithread 1 0x7f3031fc5e28 0x8bd010 :0 1 2 3 4 5 6 7 8 9
Run Code Online (Sandbox Code Playgroud)
现在我们看到每个线程都有自己的私有a,但是,与静态数组不同,每个线程仍然指向SAME内存地址.因此指针是私有的,但它们指向的地址是相同的.这实际上意味着内存仍然是共享的.
如何分配私有版本的动态数组
要为每个线程获取私有版本的动态数组,我不建议将它们分配到并行区域之外.原因是,如果你不小心,很容易造成虚假分享.请参阅此问题/答案关于通过在并行区域外部分配内存而导致的错误共享OpenMP实现的减少.您可以使用双指针,但这不一定能解决错误共享问题,并且不会解决多插槽系统上的其他问题.在这些系统上,套接字不共享同一页面(或者您获得另一种虚假共享)非常重要.如果让每个线程分配其内存,您不必担心这一点.
通常,我会为每个线程分配一个数组的私有版本,然后将它们合并到一个关键部分.但是,有些情况只能分配一次,但是在没有使用临界区的情况下,与OpenMP并行填充直方图(数组缩减)是很复杂的.
| 归档时间: |
|
| 查看次数: |
3520 次 |
| 最近记录: |