我想并行化一个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然后必须是一个全局变量,这会弄乱多线程。但是,如果有人建议在不使用嵌套函数的情况下实现相同的结果,那将是非常受欢迎的。
答案 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版本 他们都接受了不同的论点。