我使用OpenMP和MPI来并行化c中的一些矩阵运算.在矩阵上运行的一些函数是用Fortran编写的.Fortran函数需要传递一个缓冲区数组,该缓冲区数组仅在函数内部使用.目前我在每个并行部分分配缓冲区,类似于下面的代码.
int i = 0;
int n = 1024; // Actually this is read from command line
double **a = createNbyNMat(n);
#pragma omp parallel
{
double *buf;
buf = malloc(sizeof(double)*n);
#pragma omp for
for (i=0; i < n; i++)
{
fortranFunc1_(a[i], &n, buf);
}
free(z);
}
// Serial code and moving data around in the matrix a using MPI
#pragma omp parallel
{
double *buf;
buf = malloc(sizeof(double)*n);
#pragma omp for
for (i=0; i < n; i++)
{
fortranFunc2_(a[i], &n, buf);
}
free(z);
}
// and repeat a few more times.
Run Code Online (Sandbox Code Playgroud)
我知道使用类似于下面的代码的方法可以避免重新分配缓冲区,但我很好奇是否有更简单的方法或OpenMP中的一些内置功能来处理它.无论是否在我们正在编译的系统上存在OpenMP,能够在没有大量编译器指令的情况下编译代码将是很好的.
double **buf;
buf = malloc(sizeof(double*) * num_openmp_threads);
int i = 0;
for (i = 0; i < num_openmp_threads; ++i)
{
buf[i] = malloc(sizeof(double) * n);
}
// skip ahead
#pragma omp for
for (i=0; i < n; i++)
{
fortranFunc1_(a[i], &n, buf[current_thread_num]);
}
Run Code Online (Sandbox Code Playgroud)
可以使用线程私有变量来完成它.那些在后续parallel地区持续存在:
void func(...)
{
static double *buf;
#pragma omp threadprivate(buf)
#pragma omp parallel num_threads(nth)
{
buf = malloc(n * sizeof(double));
...
}
#pragma omp parallel num_threads(nth)
{
// Access buf here - it is still allocated
}
#pragma omp parallel num_threads(nth)
{
// Free the memory in the last parallel region
free(buf);
}
}
Run Code Online (Sandbox Code Playgroud)
这里有几个要点需要注意.首先,分配的线程数buf应该与解除分配它的线程数相匹配.此外,如果中间存在并行区域并且它们与较大的团队一起执行,则buf可能不会在所有区域中分配.因此,建议禁用OpenMP的动态团队大小功能,或者只使用num_threads上面所示的子句来修复每个并行区域的线程数.
其次,局部变量只有在静态时才能成为线程私有的.因此,该方法不适用于递归函数.
即使禁用了OpenMP支持,代码也应按预期编译和工作.