简体   繁体   English

使用 OpenMP 减少数组会导致“未找到用户定义的减少”

[英]Array reduction with OpenMP leads to “user defined reduction not found for”

I'm doing a scholar work and I have to obtain the histogram from a IMAGE.我正在做一项学术工作,我必须从图像中获取直方图。

All is going well, but when I tried to make the code parallel with the OpenMP, the compiler returns me this error: user defined reduction not found for 'histog'一切进展顺利,但是当我尝试使代码与 OpenMP 并行时,编译器返回此错误: user defined reduction not found for 'histog'

The code that I used is this:我使用的代码是这样的:

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]]++;
            }
        }
    }
}

And the call to the function in Main is: HistogramaParaleloRed(histog_pal_red);在 Main 中对 function 的调用是: HistogramaParaleloRed(histog_pal_red);

The error错误

user defined reduction not found for

can happen because either the code was compiled with a compiler that does not support the OpenMP 4.5 array reduction feature (or that compiler is misconfigured) or because your are trying the reduce a naked pointer ( like it is the case of your example ).可能会发生,因为代码是使用不支持OpenMP 4.5数组缩减功能的编译器编译的(或者该编译器配置错误),或者因为您正在尝试缩减指针(就像您的示例一样)。 In the latter, the compiler cannot tell how many elements are to be reduce.在后者中,编译器无法确定要减少多少元素。

So either you use a compiler that supports OpenMP 5.0 and take advantage of array sections feature as follows:因此,您可以使用支持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]]++;
            }
        }
    }
}

or alternatively, implement the reduction yourself.或者,自己实施减少。

Implement the Reduction manually手动实施归约

One approach is to create a shared structure among threads ( ie, thread_histog ), then each thread updates its position, and afterward, threads reduce the values of the shared structure into the original histog array.一种方法是在线程之间创建一个共享结构(thread_histog ),然后每个线程更新它的position,然后,线程将共享结构的值减少到原始的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]
    }
}

Another approach is to create an array of locks, one for each element of the histog array.另一种方法是创建一个锁数组,一个用于histog数组的每个元素。 Whenever a thread updates a given histog position, first acquires the lock corresponded to that position so that no other thread will be updating concurrently the same array position.每当一个线程更新给定的histog时,首先获取对应于该 position 的锁,这样其他线程就不会同时更新同一个数组 position。

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]);
    }
}

The error is attempting to directly reduce the argument pointer int *histog .该错误试图直接减少参数指针int *histog You must instead reduce a local array , and copy over the reduced results to 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];
        }
    }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM