使用OpenMP进行数组缩减导致“未找到用户定义的缩减”错误。

4

我正在进行一项学术工作,需要从图像获取直方图。

一切进展顺利,但当我尝试使用OpenMP并行化代码时,编译器会返回如下错误:user defined reduction not found for 'histog'

我使用的代码如下:

void HistogramaParaleloRed(int *histog)
{

    #pragma omp parallel
    {
        #pragma omp for
        for (int i = 0; i < NG; i++)
        {
            histog[i] = 0;
        }

        #pragma omp for reduction(+ : histog)
        for (int i = 0; i < N; i++)
        {
            for (int j = 0; j < N; j++)
            {
                histog[IMAGEN[i][j]]++;
            }
        }
    }
}

在主函数中调用该函数的方式为:HistogramaParaleloRed(histog_pal_red);

2个回答

4

错误

user defined reduction not found for

这可能是由于编译器不支持OpenMP 4.5的数组约简特性(或编译器配置错误),或者您试图缩减一个裸指针(就像您示例中所示)导致的。在后一种情况下,编译器无法确定要缩减多少个元素。

因此,您需要使用支持OpenMP 5.0的编译器,并利用数组段特性,如下:

void HistogramaParaleloRed(int *histog)
{

    #pragma omp parallel
    {
        #pragma omp for
        for (int i = 0; i < NG; i++)
        {
            histog[i] = 0;
        }

        #pragma omp for reduction(+ : histog[:N])
        for (int i = 0; i < N; i++)
        {
            for (int j = 0; j < N; j++)
            {
                histog[IMAGEN[i][j]]++;
            }
        }
    }
}

或者,手动实现这个降低操作。

手动实现降低操作

一种方法是在线程之间创建一个共享结构(即thread_histog),然后每个线程更新自己的位置,然后将共享结构的值降低到原始的histog数组中。

void HistogramaParaleloRed(int *histog, int number_threads)
{
    int thread_histog[number_threads][NG] = {{0}};
    #pragma omp parallel
    {
        int thread_id = omp_get_thread_num();
        #pragma omp for 
        for (int i = 0; i < N; i++)
          for (int j = 0; j < N; j++)
                thread_histog[thread_id][IMAGEN[i][j]]++;

       #pragma omp for no_wait
       for (int i = 0; i < NG; i++)
           for(int j = 0; j < number_threads; j++)
              histog[i] += thread_histog[j][i]
    }
}

另一种方法是创建锁的数组,其中每个锁都对应于 histog 数组的一个元素。每当线程更新给定的 histog 位置时,它首先获取该位置对应的锁,以确保没有其他线程会同时更新相同的数组位置。
void HistogramaParaleloRed(int *histog)
{
    omp_lock_t locks[NG];
    #pragma omp parallel
    {
       #pragma omp for
       for (int i = 0; i < NG; i++)
            omp_init_lock(&locks[i]);

        int thread_id = omp_get_thread_num();
        #pragma omp for 
        for (int i = 0; i < N; i++)
          for (int j = 0; j < N; j++){
              int pos = IMAGEN[i][j]
              omp_set_lock(&locks[pos]);
              thread_histog[thread_id][pos]++; 
              omp_unset_lock(&locks[pos]);
          }

       #pragma omp for no_wait
       for (int i = 0; i < NG; i++)
            omp_destroy_lock(&locks[i]);
    }
}

2
嗨!谢谢你的回答,很有效!你说得对,我重新安装了编译器,问题就解决了。干杯! - Christian Leyva

2
错误在于试图直接减少参数指针int *histog。您必须改为减少本地数组,并将减少的结果复制到histog中。
void HistogramaParaleloRed(int *histog)
{
    int localHistog[NG];

    /*
     * your code as before, replacing histog with localHistog
     */

    #pragma omp parallel
    {
        #pragma omp for
        for (int i = 0; i < NG; i++)
        {
            localHistog[i] = 0;
        }

        #pragma omp for reduction(+ : localHistog)
        for (int i = 0; i < N; i++)
        {
            for (int j = 0; j < N; j++)
            {
                localHistog[IMAGEN[i][j]]++;
            }
        }

        /* 
         * copy localHistog into output histog
         */

        #pragma omp for
        for (int i = 0; i < NG; i++)
        {
            histog[i] = localHistog[i];
        }
    }
}

2
感谢您指出我的错误,您还可以使用OpenMP 5.0的“数组片段特性”,避免手动减少。 - dreamcrash

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接