【问题标题】:Array reduction with OpenMP leads to "user defined reduction not found for"使用 OpenMP 减少数组会导致“未找到用户定义的减少”
【发布时间】:2021-04-27 09:00:14
【问题描述】:

我正在做学术工作,我必须从 IMAGE 中获取直方图。

一切顺利,但当我尝试使代码与 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]]++;
            }
        }
    }
}

而Main中函数的调用是:HistogramaParaleloRed(histog_pal_red);

【问题讨论】:

    标签: c multithreading parallel-processing openmp reduction


    【解决方案1】:

    错误

    user defined reduction not found for
    

    可能会发生,因为代码是使用不支持 OpenMP 4.5 数组缩减功能的编译器编译的(或者编译器配置错误),或者因为您正在尝试缩减 naked 指针( 就像你的例子一样)。在后者中,编译器无法告诉要减少多少元素。

    因此,您要么使用支持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]]++;
                }
            }
        }
    }
    

    或者,您也可以自己实施缩减。

    手动实施缩减

    一种方法是在线程之间创建一个共享结构(ie, 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】:

    错误是试图直接减少参数指针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];
            }
        }
    }
    

    【讨论】:

    • 感谢您指出我的错误,您还可以使用 OpenMP 5.0 中的“数组部分功能”,避免手动减少
    猜你喜欢
    • 2014-09-12
    • 2013-12-23
    • 2017-03-22
    • 1970-01-01
    • 2014-10-28
    • 1970-01-01
    • 2011-12-29
    • 1970-01-01
    • 2020-03-27
    相关资源
    最近更新 更多