欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

OpenMP 共享內存的并行編程框架入門詳解

 更新時間:2022年11月11日 14:53:00   作者:一無是處的研究僧  
這篇文章主要為大家介紹了OpenMP 共享內存的并行編程框架入門詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪

簡介

OpenMP 一個非常易用的共享內存的并行編程框架,它提供了一些非常簡單易用的API,讓編程人員從復雜的并發(fā)編程當中釋放出來,專注于具體功能的實現。openmp 主要是通過編譯指導語句以及他的動態(tài)運行時庫實現,在本篇文章當中我們主要介紹 openmp 一些入門的簡單指令的使用。

認識 openmp 的簡單易用性

比如現在我們有一個任務,啟動四個線程打印 hello world,我們看看下面 C 使用 pthread 的實現以及 C++ 使用標準庫的實現,并對比他們和 openmp 的實現復雜性。

C 語言實現

#include <stdio.h>
#include <pthread.h>
void* func(void* args) {
  printf("hello world from tid = %ld\n", pthread_self());
  return NULL;
}
int main() {
  pthread_t threads[4];
  for(int i = 0; i < 4; i++) {
    pthread_create(&threads[i], NULL, func, NULL);
  }
  for(int i = 0; i < 4; i++) {
    pthread_join(threads[i], NULL);
  }
  return 0;
}

上面文件編譯命令:gcc 文件名 -lpthread 。

C++ 實現

#include <thread>
#include <iostream>
void* func() {
  printf("hello world from %ld\n", std::this_thread::get_id());
  return 0;
}
int main() {
  std::thread threads[4];
  for(auto &t : threads) {
    t = std::thread(func);
  }
  for(auto &t : threads) {
    t.join();
  }
  return EXIT_SUCCESS;
}

上面文件編譯命令:g++ 文件名 lpthread 。

OpenMP 實現

#include <stdio.h>
#include <omp.h>
int main() {
  // #pragma 表示這是編譯指導語句 表示編譯器需要對下面的并行域進行特殊處理 omp parallel 表示下面的代碼區(qū)域 {} 是一個并行域 num_threads(4) 表示一共有 4 個線程執(zhí)行 {} 內的代碼 因此實現的效果和上面的效果是一致的
  #pragma omp parallel num_threads(4)
  {
    printf("hello world from tid = %d\n", omp_get_thread_num()); // omp_get_thread_num 表示得到線程的線程 id
  }
  return 0;
}

上面文件編譯命令:gcc 文件名 -fopenmp ,如果你使用了 openmp 的編譯指導語句的話需要在編譯選項上加上 -fopenmp。

從上面的代碼來看,確實 openmp 寫并發(fā)程序的復雜度確實比 pthreadC++ 低。openmp 相比起其他構建并行程序的方式來說,使用 openmp 你可以更加關注具體的業(yè)務實現,而不用太關心并發(fā)程序背后的啟動與結束的過程,OenpMP 會幫我們實現很多細節(jié),讓程序的執(zhí)行符合我們的直覺。

opnemp 基本原理

在上文當中我們寫了一個非常簡單的 openmp 程序,使用 4 個不同的線程分別打印 hello world 。我們仔細分析一下這個程序的執(zhí)行流程:

在 openmp 的程序當中,你可以將程序用一個個的并行域分開,在并行域(parallel region)中,程序是有并發(fā)的,但是在并行域之外是沒有并發(fā)的,只有主線程(master)在執(zhí)行,整個過程如下圖所示:

現在我們用一個程序去驗證上面的過程:

#include <stdio.h>
#include <omp.h>
#include <unistd.h>
int main() {
  #pragma omp parallel num_threads(4)
  {
    printf("parallel region 1 thread id = %d\n", omp_get_thread_num());
    sleep(1);
  }
  printf("after parallel region 1 thread id = %d\n", omp_get_thread_num());
  #pragma omp parallel num_threads(4)
  {
    printf("parallel region 2 thread id = %d\n", omp_get_thread_num());
    sleep(1);
  }
  printf("after parallel region 2 thread id = %d\n", omp_get_thread_num());
  #pragma omp parallel num_threads(4)
  {
    printf("parallel region 3 thread id = %d\n", omp_get_thread_num());
    sleep(1);
  }
  printf("after parallel region 3 thread id = %d\n", omp_get_thread_num());
  return 0;
}

程序執(zhí)行之后的一種輸出(還有很多其他的輸出形式,因為是多線程程序,線程的輸出是不確定的)如下所示:

parallel region 1 thread id = 0
parallel region 1 thread id = 3
parallel region 1 thread id = 1
parallel region 1 thread id = 2
after parallel region 1 thread id = 0
parallel region 2 thread id = 0
parallel region 2 thread id = 2
parallel region 2 thread id = 3
parallel region 2 thread id = 1
after parallel region 2 thread id = 0
parallel region 3 thread id = 0
parallel region 3 thread id = 1
parallel region 3 thread id = 3
parallel region 3 thread id = 2
after parallel region 3 thread id = 0

從上面的輸出我們可以了解到,id = 0 的線程就是主線程,在并行域內部程序的輸出是沒有順序的,但是在并行域的外部是有序的,在并行域的開始部分程序會進行并發(fā)操作,但是在并行域的最后會有一個隱藏的同步點,等待所有線程到達這個同步點之后程序才會繼續(xù)執(zhí)行,現在再看上文當中 openmp 的執(zhí)行流圖的話就很清晰易懂了。

積分例子

現在我們使用一個簡單的函數積分的例子去具體了解 openmp 在具體的使用場景下的并行。比如我們求函數 x2x^2x2 的積分。

微元法的本質就是將曲線下方的面積分割成一個一個的非常小的長方形,然后將所有的長方形的面積累加起來,這樣得到最終的結果。

如果你不懂上面所談到的求解方法也沒關系,只需要知道我們需要使用 openmp 去計算一個計算量比較大的任務即可。根據上面微元法的公式我們有一個非常大的求和公式,如果是在單線程的情況下我們使用一個循環(huán)就可以了,但是現在我們有多個線程,那么我們可以讓每個線程求某一個區(qū)間的和,最后將各個區(qū)間的和加起來得到最終的結果,這就是在并發(fā)場景下的實現思路。

openmp 具體的實現代碼如下所示:

#include <stdio.h>
#include <omp.h>
#include <math.h>
/// @brief 計算 x^2 一部分的面積
/// @param start 線程開始計算的位置
/// @param end   線程結束計算的位置
/// @param delta 長方形的邊長
/// @return 計算出來的面積
double x_square_partial_integral(double start, double end, double delta) {
  double s = 0;
  for(double i = start; i < end; i += delta) {
    s += pow(i, 2) * delta;
  }
  return s;
}
int main() {
  int s = 0;
  int e = 10;
  double sum = 0;
  #pragma omp parallel num_threads(32) reduction(+:sum)
  {
    // 根據線程號進行計算區(qū)間的分配
    // omp_get_thread_num() 返回的線程 id 從 0 開始計數 :0, 1, 2, 3, 4, ..., 31
    double start = (double)(e - s) / 32 * omp_get_thread_num();
    double end   = (double)(e - s) / 32 * (omp_get_thread_num() + 1);
    sum = x_square_partial_integral(start, end, 0.0000001);
  }
  printf("sum = %lf\n", sum);
  return 0;
}

在上面的代碼當中 #pragma omp parallel num_threads(4) 表示啟動 4 個線程執(zhí)行 {} 中的代碼,reduction(+:sum) 表示需要對 sum 這個變量進行一個規(guī)約操作,當 openmp 中的線程遇到 reduction 子句的時候首先會拷貝一份 sum 作為本地變量,然后在并行域當中使用的就是每一個線程的本地變量,因為有 reduction 的規(guī)約操作,因此在每個線程計算完成之后還需要將每個線程本地計算出來的值對操作符 + 進行規(guī)約操作,也就是將每個線程計算得到的結果求和,最終將得到的結果賦值給我們在 main 函數當中定義的變量 sum 。最終我們打印的變量 sum 就是各個線程求和之后的結果。上面的代碼執(zhí)行過程大致如下圖所示:

注意事項:你在編譯上述程序的時候需要加上編譯選項 -fopenmp 啟動openmp 編譯選項和 -lm 鏈接數學庫。

上面程序的執(zhí)行結果如下所示:

總結

在本篇文章當中主要給大家介紹了 OpenMP 的基本使用和程序執(zhí)行的基本原理,在后續(xù)的文章當中我們將仔細介紹各種 OpenMP 的子句和指令的使用方法

以上就是OpenMP 共享內存的并行編程框架入門詳解的詳細內容,更多關于OpenMP 共享內存并行編程框架的資料請關注腳本之家其它相關文章!

相關文章

  • C++初學者之根據輸入的任何一個正整數,輸出可能被表示的連續(xù)正整數

    C++初學者之根據輸入的任何一個正整數,輸出可能被表示的連續(xù)正整數

    這篇文章主要介紹了C++初學者之根據輸入的任何一個正整數,輸出可能被表示的連續(xù)正整數的相關資料,需要的朋友可以參考下
    2016-03-03
  • C++?Boost?Accumulators累加器詳細講解

    C++?Boost?Accumulators累加器詳細講解

    Boost是為C++語言標準庫提供擴展的一些C++程序庫的總稱。Boost庫是一個可移植、提供源代碼的C++庫,作為標準庫的后備,是C++標準化進程的開發(fā)引擎之一,是為C++語言標準庫提供擴展的一些C++程序庫的總稱
    2022-11-11
  • C語言如何實現順序表(數據結構)

    C語言如何實現順序表(數據結構)

    這篇文章主要介紹了C語言如何實現順序表(數據結構)問題,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2023-08-08
  • MFC之ComboBox控件用法實例教程

    MFC之ComboBox控件用法實例教程

    這篇文章主要介紹了MFC之ComboBox控件用法,包括了ComboBox控件常見的各類用法,非常具有實用價值,需要的朋友可以參考下
    2014-09-09
  • C++封裝成DLL并調用的實現

    C++封裝成DLL并調用的實現

    本文主要介紹了C++封裝成DLL并調用的實現,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2023-03-03
  • 基于C語言實現創(chuàng)意多彩貪吃蛇游戲

    基于C語言實現創(chuàng)意多彩貪吃蛇游戲

    這篇文章主要介紹了如何利用C語言實現一個創(chuàng)意多彩貪吃蛇游戲,這是一個純C語言外加easyx庫的繪圖函數制作而成的有趣小游戲,無需引入額外資源,感興趣的可以動手嘗試一下
    2022-08-08
  • 如何解決C語言,函數名與宏沖突

    如何解決C語言,函數名與宏沖突

    本文介紹了“如何解決C語言,函數名與宏沖突”,需要的朋友可以參考一下
    2013-03-03
  • 基于C++實現高精度計時器

    基于C++實現高精度計時器

    chrono是C++ 11中的時間庫,它提供了跨平臺的高精度時鐘解決方案,精確到納秒級,本文主要為大家詳細介紹了如何使用chrono實現高精度計時器,感興趣的可以了解下
    2024-02-02
  • 類成員函數的重載、覆蓋與隱藏之間的區(qū)別總結

    類成員函數的重載、覆蓋與隱藏之間的區(qū)別總結

    以下是對類成員函數的重載、覆蓋與隱藏之間的區(qū)別進行了詳細的總結分析,需要的朋友可以過來參考下。希望對大家有所幫助
    2013-10-10
  • C++中虛函數與純虛函數的用法

    C++中虛函數與純虛函數的用法

    這篇文章主要介紹了C++中虛函數與純虛函數的用法,是非常重要的概念,需要的朋友可以參考下
    2014-08-08

最新評論