【问题标题】:How to ensure a dynamically allocated array is private in openmp如何确保动态分配的数组在openmp中是私有的
【发布时间】:2023-03-12 06:15:01
【问题描述】:

我在 Linux 机器上使用 gcc 在 C 和 openMP 中工作。在 openmp 并行 for 循环中,我可以将静态分配的数组声明为私有的。考虑代码片段:

int a[10];
#pragma omp parallel for shared(none) firstprivate(a)
for(i=0;i<4;i++){

一切都按预期进行。但如果我改为动态分配一个,

int * a = (int *) malloc(10*sizeof(int));
#pragma omp parallel for shared(none) firstprivate(a)

a(至少 a[1...9])的值不受保护,但它们的行为就像它们是共享的一样。这是可以理解的,因为 pragma 命令中似乎没有任何内容告诉 omp 需要私有的数组 a 有多大。如何将此信息传递给openmp?如何将整个动态分配的数组声明为私有?

【问题讨论】:

    标签: c malloc parallel-processing openmp


    【解决方案1】:

    我不认为你这样做 - 我为解决这个问题所做的是使用并行区域 #pragma omp parallel shared(...) private(...) 并在并行区域内动态分配数组。试试这个:

    #include <stdio.h>
    #include <stdlib.h>
    #include <malloc.h>
    
    /* compile with gcc -o test2 -fopenmp test2.c */
    
    int main(int argc, char** argv)
    {
        int i = 0;
        int size = 20;
        int* a = (int*) calloc(size, sizeof(int));
        int* b = (int*) calloc(size, sizeof(int));
        int* c;
    
        for ( i = 0; i < size; i++ )
        {
            a[i] = i;
            b[i] = size-i;
            printf("[BEFORE] At %d: a=%d, b=%d\n", i, a[i], b[i]);
        }
    
        #pragma omp parallel shared(a,b) private(c,i)
        {
            c = (int*) calloc(3, sizeof(int));
    
            #pragma omp for
            for ( i = 0; i < size; i++ )
            {
                c[0] = 5*a[i];
                c[1] = 2*b[i];
                c[2] = -2*i;
                a[i] = c[0]+c[1]+c[2];
    
                c[0] = 4*a[i];
                c[1] = -1*b[i];
                c[2] = i;
                b[i] = c[0]+c[1]+c[2];
            }
    
            free(c);
        }
    
        for ( i = 0; i < size; i++ )
        {
            printf("[AFTER] At %d: a=%d, b=%d\n", i, a[i], b[i]);
        }
    }
    

    这对我来说产生了与我之前的实验程序相同的结果:

    #include <stdio.h>
    #include <stdlib.h>
    #include <malloc.h>
    
    /* compile with gcc -o test1 -fopenmp test1.c */
    
    int main(int argc, char** argv)
    {
        int i = 0;
        int size = 20;
        int* a = (int*) calloc(size, sizeof(int));
        int* b = (int*) calloc(size, sizeof(int));
    
        for ( i = 0; i < size; i++ )
        {
            a[i] = i;
            b[i] = size-i;
            printf("[BEFORE] At %d: a=%d, b=%d\n", i, a[i], b[i]);
        }
    
        #pragma omp parallel for shared(a,b) private(i)
        for ( i = 0; i < size; i++ )
        {
            a[i] = 5*a[i]+2*b[i]-2*i;
            b[i] = 4*a[i]-b[i]+i;
        }
    
        for ( i = 0; i < size; i++ )
        {
            printf("[AFTER] At %d: a=%d, b=%d\n", i, a[i], b[i]);
        }
    }
    

    我猜测是因为 OpenMP 无法推断出数组的大小,所以它不能是私有的 - 只有编译时数组才能以这种方式完成。当我尝试私有一个动态分配的数组时,我得到了段错误,大概是因为访问冲突。在每个线程上分配数组,就像您使用 pthreads 编写的一样有意义并解决了问题。

    【讨论】:

    • 谢谢,分离 openmp 声明和并行声明似乎工作得很好。
    • @Ninefingers:我知道这篇文章已经过时了,但我有一个简短的问题。你甚至需要#pragma omp for 声明吗?无论如何,它不会并行执行该循环吗?
    • @Amit 不,你需要告诉编译器中断线程,否则它不会。
    【解决方案2】:

    您告诉 OpenMP,指针 a 是私有的,即在每个线程中复制。您的数组只是a 指向的一些任意数据,OpenMP 不会复制它(可能是因为这需要分配和取消分配复制的数组)。

    【讨论】:

    • 那么如何让 OpenMP 为每个线程创建一个数组呢?在我的例子中,每个线程都需要一个缓冲区数组。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多