跳轉至內容

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 並行化。

華夏公益教科書