OpenMP是一種用於共享內存並行系統的多線程程序設計方案,支持的編程語言包括C、C++和Fortran。OpenMP提供了對並行算法的高層抽象描述,特別適合在多核CPU機器上的並行程序設計。編譯器根據程序中添加的pragma指令,自動將程序並行處理,使用OpenMP下降了並行編程的難度和複雜度。當編譯器不支持OpenMP時,程序會退化成普通(串行)程序。程序中已有的OpenMP指令不會影響程序的正常編譯運行。ios
在VS中啓用OpenMP很簡單,不少主流的編譯環境都內置了OpenMP。在項目上右鍵->屬性->配置屬性->C/C++->語言->OpenMP支持,選擇「是」便可。算法
OpenMP採用fork-join的執行模式。開始的時候只存在一個主線程,當須要進行並行計算的時候,派生出若干個分支線程來執行並行任務。當並行代碼執行完成以後,分支線程會合,並把控制流程交給單獨的主線程。編程
一個典型的fork-join執行模型的示意圖以下:多線程
OpenMP編程模型以線程爲基礎,經過編譯製導指令制導並行化,有三種編程要素能夠實現並行化控制,他們分別是編譯製導、API函數集和環境變量。併發
編譯製導指令以#pragma omp 開始,後邊跟具體的功能指令,格式如:#pragma omp 指令[子句[,子句] …]。經常使用的功能指令以下:編程語言
除上述編譯製導指令以外,OpenMP還提供了一組API函數用於控制併發線程的某些行爲,下面是一些經常使用的OpenMP API函數以及說明: 函數
OpenMP中定義一些環境變量,能夠經過這些環境變量控制OpenMP程序的行爲,經常使用的環境變量:優化
parallel制導指令用來建立並行域,後邊要跟一個大括號將要並行執行的代碼放在一塊兒:atom
#include<iostream> #include"omp.h" using namespace std; void main() { #pragma omp parallel { cout << "Test" << endl; } system("pause"); }
執行以上程序有以下輸出:spa
程序打印出了4個「Test」,說明parallel後的語句被4個線程分別執行了一次,4個是程序默認的線程數,還能夠經過子句num_threads顯式控制建立的線程數:
#include<iostream> #include"omp.h" using namespace std; void main() { #pragma omp parallel num_threads(6) { cout << "Test" << endl; } system("pause"); }
編譯運行有以下輸出:
程序中顯式定義了6個線程,因此parallel後的語句塊分別被執行了6次。第二行的空行是因爲每一個線程都是獨立運行的,在其中一個線程輸出字符「Test」以後尚未來得及換行時,另外一個線程直接輸出了字符「Test」。
使用parallel制導指令只是產生了並行域,讓多個線程分別執行相同的任務,並無實際的使用價值。parallel for用於生成一個並行域,並將計算任務在多個線程之間分配,從而加快計算運行的速度。可讓系統默認分配線程個數,也可使用num_threads子句指定線程個數。
#include<iostream> #include"omp.h" using namespace std; void main() { #pragma omp parallel for num_threads(6) for (int i = 0; i < 12; i++) { printf("OpenMP Test, 線程編號爲: %d\n", omp_get_thread_num()); } system("pause"); }
運行輸出:
上邊程序指定了6個線程,迭代量爲12,從輸出能夠看到每一個線程都分到了12/6=2次的迭代量。
#include<iostream> #include"omp.h" using namespace std; void test() { for (int i = 0; i < 80000; i++) { } } void main() { float startTime = omp_get_wtime(); //指定2個線程 #pragma omp parallel for num_threads(2) for (int i = 0; i < 80000; i++) { test(); } float endTime = omp_get_wtime(); printf("指定 2 個線程,執行時間: %f\n", endTime - startTime); startTime = endTime; //指定4個線程 #pragma omp parallel for num_threads(4) for (int i = 0; i < 80000; i++) { test(); } endTime = omp_get_wtime(); printf("指定 4 個線程,執行時間: %f\n", endTime - startTime); startTime = endTime; //指定8個線程 #pragma omp parallel for num_threads(8) for (int i = 0; i < 80000; i++) { test(); } endTime = omp_get_wtime(); printf("指定 8 個線程,執行時間: %f\n", endTime - startTime); startTime = endTime; //指定12個線程 #pragma omp parallel for num_threads(12) for (int i = 0; i < 80000; i++) { test(); } endTime = omp_get_wtime(); printf("指定 12 個線程,執行時間: %f\n", endTime - startTime); startTime = endTime; //不使用OpenMP for (int i = 0; i < 80000; i++) { test(); } endTime = omp_get_wtime(); printf("不使用OpenMP多線程,執行時間: %f\n", endTime - startTime); startTime = endTime; system("pause"); }
以上程序分別指定了二、四、八、12個線程和不使用OpenMP優化來執行一段垃圾程序,輸出以下:
可見,使用OpenMP優化後的程序執行時間是原來的1/4左右,而且並非線程數使用越多效率越高,通常線程數達到4~8個的時候,不能簡單經過提升線程數來進一步提升效率。