OpenMP/循环
外观
< OpenMP
假设我们需要并行化以下顺序代码。
function VectorAdd(int *a, int *b, int N)
{
for(int i=0; i<N; i++)
{
a[i] = a[i] + b[i];
}
}
我们可以做的是将每个线程分配给执行迭代的子集。
#include <omp.h> // for OpenMP library
function VectorAddParallel(int *a, int *b, int N)
{
omp_set_num_threads(24);
#pragma omp parallel
{
int id, i, Nthrds, istart, iend;
id = omp_get_thread_num();
Nthrds= omp_get_num_threads();
istart= id * N / Nthrds;
iend= (id+1) * N / Nthrds;
if (id == Nthrds-1)
iend= N;
for(int i=istart;i<iend;i++)
{
a[i] = a[i] + b[i];
}
}
}
上面代码中的 omp_set_num_threads(24)
告诉计算机在进入并行区域(#pragma omp parallel
的范围)时生成 24 个线程。但是,由于资源限制和环境约束,我们不能保证会得到与我们要求的相同数量的线程。因此,我们在并行区域内调用 omp_get_num_threads()
以了解实际生成的线程数量。然后我们为每个线程分配起始和结束迭代。例如,id
为 0 的线程(由 omp_get_thread_num()
返回)将执行 istart
和 iend
之间的所有迭代。每个线程将获得循环索引变量的私有实例,以及在并行区域内声明的变量的私有实例。
我们可以使用 OpenMP 的 for
工作共享构造简化上面的函数。它可以与并行指令结合使用,如 #pragma omp parallel for
。
#include <omp.h> // for OpenMP library
function VectorAddParallelSimplified(int *a, int *b, int N)
{
#pragma omp parallel for
for(int i=0;i<N;i++)
{
a[i] = a[i] + b[i];
}
}
编译器指令 #pragma omp for
除非在并行区域内使用,否则没有效果。同样,可以安全地假设使用 OpenMP 库函数但不使用 #pragma omp parallel
的代码不会被 OpenMP 并行化。