使用C语言中的openmp,如何并行化包含qsort嵌套比较功能的for循环?

时间:2019-01-09 08:43:28

标签: c openmp qsort

我想并行化一个for循环,该循环包含用于qsort的嵌套比较函数:

#include    <stdio.h>
#include    <stdlib.h>
#include    <omp.h>

int main(){
    int i;
#pragma omp parallel for
    for(i = 0; i < 100; i++){
        int *index= (int *) malloc(sizeof(int)*10);
        double *tmp_array = (double*) malloc(sizeof(double)*10);
        int j;
        for(j=0; j<10; j++){
            tmp_array[j] = rand();
            index[j] = j;
        }
        // QuickSort the index array based on tmp_array:
        int simcmp(const void *a, const void *b){
            int ia = *(int *)a;
            int ib = *(int *)b;
            if ((tmp_array[ia] - tmp_array[ib]) > 1e-12){
                return -1;
            }else{
                return 1;
            }
        }
        qsort(index, 10, sizeof(*index), simcmp);
        free(index);
        free(tmp_array);
    }
    return 0;
}

当我尝试编译它时,出现错误:

internal compiler error: in get_expr_operands, at tree-ssa-operands.c:881
 }

据我所知,此错误是由于嵌套的比较函数引起的。有没有办法使openmp可以使用此嵌套比较功能?如果没有,有没有嵌套比较功能的好方法吗?

编辑: 我正在使用允许嵌套函数的GNU C编译器。该代码无需编译指示即可编译并正常运行。我不能在for循环之外定义simcmp,因为tmp_array然后必须是一个全局变量,这会弄乱多线程。但是,如果有人建议在不使用嵌套函数的情况下实现相同的结果,那将是非常受欢迎的。

2 个答案:

答案 0 :(得分:2)

我意识到这已经可以自我解答,但是这里有一些标准的C和OpenMP选项。 df.stack(level=0) a b c p A 0 0 0 B 0 0 0 q A 0 0 0 B 0 0 0 r A 0 0 0 B 0 0 0 s A 0 0 0 B 0 0 0 函数是一个很好的经典选择,但是值得注意的是qsort_r是c11标准的一部分,因此无论提供c11的位置都是可移植的(不包括Windows,它们并不完全提供c99)。

对于在没有嵌套比较功能的OpenMP中仍然使用原始qsort的情况,有两种方法。首先是将经典的全局变量与OpenMP qsort_s结合使用:

threadprivate

上面的版本使并行区域中的每个线程都使用全局变量index和tmp_array的私有副本,从而解决了该问题。这可能是您可以在标准C和OpenMP中编写的最可移植的版本,唯一可能不兼容的平台是那些未实现线程本地内存的平台(某些微控制器等)。

如果您想避免使用全局变量并且仍然具有可移植性并使用OpenMP,那么我建议您将C ++ 11和static int *index = NULL; static double *tmp_array = NULL; #pragma omp threadprivate(index, tmp_array) int simcmp(const void *a, const void *b){ int ia = *(int *)a; int ib = *(int *)b; double aa = ((double *)tmp_array)[ia]; double bb = ((double *)tmp_array)[ib]; if ((aa - bb) > 1e-12){ return -1; }else{ return 1; } } int main(){ int i; #pragma omp parallel for for(i = 0; i < 100; i++){ index= (int *) malloc(sizeof(int)*10); tmp_array = (double*) malloc(sizeof(double)*10); int j; for(j=0; j<10; j++){ tmp_array[j] = rand(); index[j] = j; } // QuickSort the index array based on tmp_array: qsort_r(index, 10, sizeof(*index), simcmp, tmp_array); free(index); free(tmp_array); } return 0; } 算法与lambda结合使用:

std::sort

答案 1 :(得分:1)

我用qsort_r解决了我的问题,它使您可以将其他指针传递给比较函数。

#define _GNU_SOURCE
#include    <stdio.h>
#include    <stdlib.h>
#include    <omp.h>

int simcmp(const void *a, const void *b, void *tmp_array){
    int ia = *(int *)a;
    int ib = *(int *)b;
    double aa = ((double *)tmp_array)[ia];
    double bb = ((double *)tmp_array)[ib];
    if ((aa - bb) > 1e-12){
        return -1;
    }else{
        return 1;
    }
}

int main(){
    int i;
#pragma omp parallel for
    for(i = 0; i < 100; i++){
        int *index= (int *) malloc(sizeof(int)*10);
        double *tmp_array = (double*) malloc(sizeof(double)*10);
        int j;
        for(j=0; j<10; j++){
            tmp_array[j] = rand();
            index[j] = j;
        }
        // QuickSort the index array based on tmp_array:
        qsort_r(index, 10, sizeof(*index), simcmp, tmp_array);
        free(index);
        free(tmp_array);
    }
    return 0;
}

这将编译并运行没有问题。但是,由于qsort_r依赖于平台和编译器,因此它不是完全理想的。在portable version of qsort_r here中,作者很好地总结了我的问题:

  

如果要使用比较运算符对数组进行qsort(),   您需要使用全局变量传递这些参数的参数   (在编写多线程代码时不可能),或使用qsort_r / qsort_s   不能移植(有单独的GNU / BSD / Windows版本   他们都接受了不同的论点。