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