OpenMP中的本地指针

局部变量应该对每个线程自动私有。 如何将本地指针指向并行区域之外的某个地址,例如

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 x = 1.0f; // ... } } delete[]a; 

我应该将local_a私有和私人私人? 我实际上是OpenMP和C的新手。

这取决于你想对数组做什么。 每个线程是否应该访问相同的数组,而不需要将指针设置为threadprivate。

在你的情况下,如果你设置a私有,无关紧要,因为指针只将地址存储到内存中。 如果所有线程使用相同的变量来访问相同的地址,或者如果每个线程都有自己的相同地址的副本,则没有区别。

如果每个线程都应该有自己的数组副本,那么您需要分别为每个线程分配和删除内存。 如果您的编译器支持为线程私有对象调用已创建的C ++对象的正确构造函数,则可以在您的情况下使用std :: vector。

 std::vector a; #pragma omp parallel for firstprivate(a) for (j = 0; j < 10; j++) { A * local_j = &a[j]; local_j->x = 1.0f; // ... } 

否则,您需要为每个线程分配一个单独的内存块。

 const int num_threads = omp_get_num_threads(); A** a; a = new A*[num_threads]; for (int i=0; ix = 1.0f; // ... } for (int i=0; i 

重要的是要知道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 

请注意,每个线程的地址都相同。 现在让我们尝试传递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 

现在每个线程都有其唯一的私有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 

现在唯一的区别是复制a ARE的值。

动态数组:

 int *a = new int[10]; for(int i=0; i<10; i++) a[i]=i; 

让我们先看看传递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 

每个线程都具有相同的静态数组。 当我们使用私有时,会发生差异。

 #pragma omp parallel private(a) //segmentation fault 

每个线程都有自己的私有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 

现在我们看到每个线程都有自己的私有a ,但是,与静态数组不同,每个线程仍然指向SAME内存地址。 所以指针是私有的,但它们指向的地址是相同的。 这实际上意味着内存仍然是共享的。

如何分配私有版本的动态数组

要为每个线程获取私有版本的动态数组,我不建议将它们分配到并行区域之外。 原因是,如果你不小心,很容易造成虚假分享。 请参阅此问题/答案关于通过在并行区域外部分配内存而导致的错误共享OpenMP实现的减少 。 您可以使用双指针,但这不一定能解决错误共享问题,并且不会解决多插槽系统上的其他问题。 在这些系统上,套接字不共享同一页面(或者您获得另一种虚假共享)非常重要。 如果让每个线程分配其内存,您不必担心这一点。

一般来说,我会为每个线程分配一个数组的私有版本,然后将它们合并到一个关键部分。 但是,有些情况只能分配一次,但是在不使用临界区的情况下,与OpenMP并行填充直方图(数组缩减)是很复杂的。