https://zhuanlan.zhihu.com/p/51173703
最近,有個課設關於提取SIFT特征,老師要求不能使用OpenCV,從底層實現SIFT特征,在實現的過程中,參考了很多人的思路,其中有一個是對代碼進行並行優化,引起了我的興趣,所以找了一些資料來詳細認識下OpenMP的使用~~
參考文章:
OpenMP並行程序設計(二) - 周偉明的多核、測試專欄 - CSDN博客
標准並行模式執行代碼的基本思想是,程序開始時只有一個主線程,程序中的串行部分都由主線程執行,並行的部分是通過派生其他線程來執行,但是如果並行部分沒有結束時是不會執行串行部分的~
開發環境:VS2015,注意使用時要將OpenMP打開,並且#include "omp"
在C++中,OpenMP的指令格式為:#pragma omp指令[子句[子句]…]
例如: #pragma omp parallel private(i, j)
parallel 就是指令, private是子句
1. OpenMP的指令
OpenMP的指令有以下一些:(常用的已標黑)
- parallel,用在一個代碼段之前,表示這段代碼將被多個線程並行執行
- for,用於for循環之前,將循環分配到多個線程中並行執行,必須保證每次循環之間無相關性。
- parallel for, parallel 和 for語句的結合,也是用在一個for循環之前,表示for循環的代碼將被多個線程並行執行。
- sections,用在可能會被並行執行的代碼段之前
- parallel sections,parallel和sections兩個語句的結合
- critical,用在一段代碼臨界區之前
- single,用在一段只被單個線程執行的代碼段之前,表示后面的代碼段將被單線程執行。
- flush,
- barrier,用於並行區內代碼的線程同步,所有線程執行到barrier時要停止,直到所有線程都執行到barrier時才繼續往下執行。
- atomic,用於指定一塊內存區域被制動更新
- master,用於指定一段代碼塊由主線程執行
- ordered, 用於指定並行區域的循環按順序執行
- threadprivate, 用於指定一個變量是線程私有的。
例子1:
#include <iostream>
#include "omp.h"
using namespace std;
int main(int argc, char **argv) {
//設置線程數,一般設置的線程數不超過CPU核心數,這里開4個線程執行並行代碼段
omp_set_num_threads(4);
#pragma omp parallel
{
cout << "Hello" << ", I am Thread " << omp_get_thread_num() << endl;
}
}
結果1:
Hello, I am Thread 1
Hello, I am Thread 0
Hello, I am Thread 2
Hello, I am Thread 3
例子2:(帶for的指令)
#include <iostream> #include "omp.h" using namespace std; int main() { omp_set_num_threads(4); #pragma omp parallel for (int i = 0; i < 3; i++) printf("i = %d, I am Thread %d\n", i, omp_get_thread_num()); getchar(); }
結果2:
i = 0, I am Thread 0
i = 1, I am Thread 0
i = 2, I am Thread 0
i = 0, I am Thread 0
i = 0, I am Thread 0
i = 0, I am Thread 0
i = 1, I am Thread 0
i = 2, I am Thread 0
i = 1, I am Thread 0
i = 2, I am Thread 0
i = 1, I am Thread 0
i = 2, I am Thread 0
例子3:
#include <iostream>
#include "omp.h"
using namespace std;
int main() {
omp_set_num_threads(4);
#pragma omp parallel for
for (int i = 0; i < 3; i++)
printf("i = %d, I am Thread %d\n", i, omp_get_thread_num());
getchar();
}
結果3:
i = 0, I am Thread 0
i = 1, I am Thread 1
i = 2, I am Thread 2
注意注意:例子三和例子二的區別和不同
2. OpenMP的常用庫函數
omp_get_num_procs, 返回運行本線程的多處理機的處理器個數。
omp_get_num_threads, 返回當前並行區域中的活動線程個數。
omp_get_thread_num, 返回線程號
omp_set_num_threads, 設置並行執行代碼時的線程個數
omp_init_lock, 初始化一個簡單鎖
omp_set_lock, 上鎖操作
omp_unset_lock, 解鎖操作,要和omp_set_lock函數配對使用。
omp_destroy_lock, omp_init_lock函數的配對操作函數,關閉一個鎖
如果在VS2015中運行時,首先要先做一個判斷,編譯器是否支持OpenMP,在下圖中把其打開,然后在程序中做一個判斷語句:
#ifdef _OPENMP //判斷是否定義
omp_lock_t lock;
omp_init_lock(&lock);
#endif
設置打開OpenMP:
3. OpenMP的子句
private, 指定每個線程都有它自己的變量私有副本。
firstprivate,指定每個線程都有它自己的變量私有副本,並且變量要被繼承主線程中的初值。
lastprivate,主要是用來指定將線程中的私有變量的值在並行處理結束后復制回主線程中的對應變量。
reduce,用來指定一個或多個變量是私有的,並且在並行處理結束后這些變量要執行指定的運算。
nowait,忽略指定中暗含的等待
num_threads,指定線程的個數
schedule,指定如何調度for循環迭代
shared,指定一個或多個變量為多個線程間的共享變量
ordered,用來指定for循環的執行要按順序執行
copyprivate,用於single指令中的指定變量為多個線程的共享變量
copyin,用來指定一個threadprivate的變量的值要用主線程的值進行初始化。
default,用來指定並行處理區域內的變量的使用方式,缺省是shared
其實,實際中做優化時會考慮的更多更復雜,不過自己的代碼優化的話,一般也就是優化for循環多一些,比較簡單。具體使用時再進行查找深入了解~