天天看點

極智Coding | OpenMP 多線程使用

  ​

​歡迎關注我的公衆号 [極智視界],擷取我的更多筆記分享​

  大家好,我是極智視界,本文講解一下 OpenMP 多線程使用方法。

  OpenMP 是一種用于共享記憶體并行系統的多線程程式設計方案,其提供了對并行算法的高層抽象描述,特别适合在多核 CPU 機器上的并行程式設計。編譯器根據程式中添加的 pragma 指令,自動将程式并行處理,使用 OpenMP 降低了并行程式設計的難度和複雜度。當編譯器不支援 OpenMP 時,程式會退化成普通(串行)程式,程式中已有的 OpenMP 指令不會影響程式的正常編譯運作。

文章目錄

  • ​​1 OpenMP 常用指令​​
  • ​​2 OpenMP 使用示例​​

1 OpenMP 常用指令

  使用 OpenMP 時需要引入 ​

​omp.h​

​​ 頭檔案,然後在編譯時添加參數 ​

​-fopenmp​

​​ 即可。在具體需要進行并行運算的部分,使用 ​

​#pragma omp​

​ 指令[子句] 來告訴編譯器如何并行執行對應的語句。

  常用的指令如下:

  • parallel:即​

    ​#pragma omp parallel​

    ​​ 後面需要有一個代碼片段,使用​

    ​{}​

    ​ 括起來,表示會被并行執行;
  • parallel for:這裡後面接​

    ​for​

    ​ 語句即可,不需要有額外的代碼塊;
  • sections;
  • parallel sections;
  • single:表示隻能單線程執行;
  • critical:臨界區,表示每次隻能有一個 openmp 線程進入;
  • barrier:用于并行域内代碼的線程同步,線程執行到 barrier 時停下來,直到所有線程都執行到barrier時才繼續;

  常用的子句如下:

  • num_threads:指定并行域内線程的數目;
  • shared:指定一個或者多個變量為多個線程的共享變量;
  • private:指定一個變量或者多個變量在每個線程中都有它的副本;

  另外,openmp 還提供了一些列的 API 函數來擷取并行線程的狀态或控制并行線程的行為,常用 API 如下:

  • omp_in_parallel:判斷目前是否在并行域中;
  • omp_get_thread_num:擷取線程号;
  • omp_set_num_threads:設定并行域中線程格式;
  • omp_get_num_threads:傳回并行域中線程數;
  • omp_get_dynamic:判斷是否支援動态改變線程數目;
  • omp_get_max_threads: 擷取并行域中可用的最大的并行線程數目;
  • omp_get_num_procs:傳回系統中處理器的個數;

2 OpenMP 使用示例

  這裡介紹一個計算圓周率的示例:

#include <stdio.h>
#include <omp.h>
 
#define MAX_THREADS 4
 
static long num_steps = 100000000;
double step;

int spmd(){
    int i,j;
    double pi, full_sum = 0.0;
    double start_time, run_time;
    double sum[MAX_THREADS];
    step = 1.0/(double) num_steps;
 
    for(j=1;j<=MAX_THREADS ;j++){
        omp_set_num_threads(j);
        full_sum = 0.0;
        start_time = omp_get_wtime();
      
#pragma omp parallel private(i)
      {
        int id = omp_get_thread_num();
        int numthreads = omp_get_num_threads();
        double x;
        double partial_sum = 0;
#pragma omp single
        printf(" num_threads = %d",numthreads);
        for (i=id;i< num_steps; i+=numthreads){
            x = (i+0.5)*step;
            partial_sum += + 4.0/(1.0+x*x);
        }
#pragma omp critical
        full_sum += partial_sum;
}
      
        pi = step * full_sum;
        run_time = omp_get_wtime() - start_time;
        printf("\n pi is %f in %f seconds %d threds \n ",pi,run_time,j);
    }
}

int openMP(){
    int i;
    double x, pi, sum = 0.0;
    double start_time, run_time;
 
    step = 1.0/(double) num_steps;
    for (i=1;i<=4;i++){
        sum = 0.0;
        omp_set_num_threads(i);
        start_time = omp_get_wtime();
#pragma omp parallel
      {
#pragma omp single
        printf(" num_threads = %d",omp_get_num_threads());
#pragma omp for reduction(+:sum)
        for (i=1;i<= num_steps; i++){
            x = (i-0.5)*step;
            sum = sum + 4.0/(1.0+x*x);
        }
      }
        pi = step * sum;
        run_time = omp_get_wtime() - start_time;
        printf("\n pi is %f in %f seconds and %d threads\n",pi,run_time,i);
    }
}  

int main() {
    spmd();
    printf("openMP Loop Paralelism:\n");
    openMP();
    return 0;
}      

  運作結果如下:

極智Coding | OpenMP 多線程使用

  好了,以上分享了 OpenMP 多線程使用方法。希望我的分享能對你的學習有一點幫助。

極智Coding | OpenMP 多線程使用