跳转至内容

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() 返回)将执行 istartiend 之间的所有迭代。每个线程将获得循环索引变量的私有实例,以及在并行区域内声明的变量的私有实例。

我们可以使用 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 并行化。

华夏公益教科书