成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

OpenMP并行程序設計(二)

開發 前端
OpenMP是一個編譯器指令和庫函數的集合,主要是為共享式存儲計算機上的并行程序設計使用的。

1.fork/join并行執行模式的概念

OpenMP是一個編譯器指令和庫函數的集合,主要是為共享式存儲計算機上的并行程序設計使用的。

前 面一篇文章中已經試用了OpenMP的一個Parallel for指令。從上篇文章中我們也可以發現OpenMP并行執行的程序要全部結束后才能執行后面的非并行部分的代碼。這就是標準的并行模式 fork/join式并行模式,共享存儲式并行程序就是使用fork/join式并行的。

標準并行模式執行代碼的基本思想是,程序開始時只有一個主線程,程序中的串行部分都由主線程執行,并行的部分是通過派生其他線程來執行,但是如果并行部分沒有結束時是不會執行串行部分的,如上一篇文章中的以下代碼:

  1. int main(int argc, char* argv[]) 
  2.      clock_t t1 = clock(); 
  3. #pragma omp parallel for 
  4.      for ( int j = 0; j < 2; j++ ){ 
  5.          test(); 
  6.      } 
  7.      clock_t t2 = clock(); 
  8.      printf("Total time = %d/n", t2-t1); 
  9.   
  10.      test(); 
  11.      return 0; 
在沒有執行完for循環中的代碼之前,后面的clock_t t2 = clock();這行代碼是不會執行的,如果和調用線程創建函數相比,它相當于先創建線程,并等待線程執行完,所以這種并行模式中在主線程里創建的線程并沒有和主線程并行運行。

2.OpenMP指令和庫函數介紹

下面來介紹OpenMP的基本指令和常用指令的用法,

在C/C++中,OpenMP指令使用的格式為

       #pragma omp 指令 [子句[子句]…]

前面提到的parallel for就是一條指令,有些書中也將OpenMP的“指令”叫做“編譯指導語句”,后面的子句是可選的。例如:

#pragma omp parallel private(i, j)

parallel 就是指令, private是子句

為敘述方便把包含#pragma和OpenMP指令的一行叫做語句,如上面那行叫parallel語句。

 

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, 用于指定一個變量是線程私有的。

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函數的配對操作函數,關閉一個鎖

OpenMP的子句有以下一些

private, 指定每個線程都有它自己的變量私有副本。

firstprivate,指定每個線程都有它自己的變量私有副本,并且變量要被繼承主線程中的初值。

lastprivate,主要是用來指定將線程中的私有變量的值在并行處理結束后復制回主線程中的對應變量。

reduce,用來指定一個或多個變量是私有的,并且在并行處理結束后這些變量要執行指定的運算。

nowait,忽略指定中暗含的等待

num_threads指定線程的個數

schedule,指定如何調度for循環迭代

shared,指定一個或多個變量為多個線程間的共享變量

ordered,用來指定for循環的執行要按順序執行

copyprivate,用于single指令中的指定變量為多個線程的共享變量

copyin用來指定一個threadprivate的變量的值要用主線程的值進行初始化。

default,用來指定并行處理區域內的變量的使用方式,缺省是shared

3.parallel 指令的用法

parallel 是用來構造一個并行塊的,也可以使用其他指令如for、sections等和它配合使用。

在C/C++中,parallel的使用方法如下:

  1. #pragma omp parallel [for | sections] [子句[子句]…] 
  2.        //代碼 
  3. parallel語句后面要跟一個大括號對將要并行執行的代碼括起來。 
  4. void main(int argc, char *argv[]) { 
  5. #pragma omp parallel 
  6.               printf(“Hello, World!/n”); 
  7. 執行以上代碼將會打印出以下結果 
  8. Hello, World! 
  9. Hello, World! 
  10. Hello, World! 
  11. Hello, World! 
  12. 可以看得出parallel語句中的代碼被執行了四次,說明總共創建了4個線程去執行parallel語句中的代碼。 
  13. 也可以指定使用多少個線程來執行,需要使用num_threads子句: 
  14. void main(int argc, char *argv[]) { 
  15. #pragma omp parallel num_threads(8) 
  16.               printf(“Hello, World!, ThreadId=%d/n”, omp_get_thread_num() ); 
  17. 執行以上代碼,將會打印出以下結果: 
  18. Hello, World!, ThreadId = 2 
  19. Hello, World!, ThreadId = 6 
  20. Hello, World!, ThreadId = 4 
  21. Hello, World!, ThreadId = 0 
  22. Hello, World!, ThreadId = 5 
  23. Hello, World!, ThreadId = 7 
  24. Hello, World!, ThreadId = 1 
  25. Hello, World!, ThreadId = 3 

ThreadId的不同可以看出創建了8個線程來執行以上代碼。所以parallel指令是用來為一段代碼創建多個線程來執行它的。parallel塊中的每行代碼都被多個線程重復執行。

和傳統的創建線程函數比起來,相當于為一個線程入口函數重復調用創建線程函數來創建線程并等待線程執行完。

4.for指令的使用方法

for指令則是用來將一個for循環分配到多個線程中執行。for指令一般可以和parallel指令合起來形成parallel for指令使用,也可以單獨用在parallel語句的并行塊中。

#pragma omp [parallel] for [子句]

      for循環語句

先看看單獨使用for語句時是什么效果:

  1. 先看看單獨使用for語句時是什么效果: 
  2. int j = 0
  3. #pragma omp for 
  4.      for ( j = 0; j < 4; j++ ){ 
  5.          printf(“j = %d, ThreadId = %d/n”, j, omp_get_thread_num()); 
  6.      } 
  7. 執行以上代碼后打印出以下結果 
  8. j = 0ThreadId = 0 
  9. j = 1ThreadId = 0 
  10. j = 2ThreadId = 0 
  11. j = 3ThreadId = 0 
  12. 從結果可以看出四次循環都在一個線程里執行,可見for指令要和parallel指令結合起來使用才有效果: 
  13. 如以下代碼就是parallel 和for一起結合成parallel for的形式使用的: 
  14. int j = 0
  15. #pragma omp parallel for 
  16.      for ( j = 0; j < 4; j++ ){ 
  17.          printf(“j = %d, ThreadId = %d/n”, j, omp_get_thread_num()); 
  18.      } 
  19. 執行后會打印出以下結果: 
  20. j = 0ThreadId = 0 
  21. j = 2ThreadId = 2 
  22. j = 1ThreadId = 1 
  23. j = 3ThreadId = 3 
  24. 可見循環被分配到四個不同的線程中執行。 
  25.   
  26. 上面這段代碼也可以改寫成以下形式: 
  27. int j = 0
  28. #pragma omp parallel 
  29. #pragma omp for 
  30.      for ( j = 0; j < 4; j++ ){ 
  31.          printf(“j = %d, ThreadId = %d/n”, j, omp_get_thread_num()); 
  32.      } 

 執行以上代碼會打印出以下結果:

j = 1, ThreadId = 1

j = 3, ThreadId = 3

j = 2, ThreadId = 2

j = 0, ThreadId = 0

在一個parallel 塊中也可以有多個for語句,如:

  1. int j; 
  2. #pragma omp parallel 
  3. #pragma omp for 
  4.      for ( j = 0; j < 100; j++ ){ 
  5.          … 
  6.      } 
  7. #pragma omp for 
  8.      for (  j = 0; j < 100; j++ ){ 
  9.          … 
  10.      } 
  11. … 

for 循環語句中,書寫是需要按照一定規范來寫才可以的,即for循環小括號內的語句要按照一定的規范進行書寫,for語句小括號里共有三條語句

for( i=start; i < end; i++)

i=start; 是for循環里的第一條語句,必須寫成 “變量=初值” 的方式。如 i=0

i < end;是for循環里的第二條語句,這個語句里可以寫成以下4種形式之一:

變量 < 邊界值

變量 <= 邊界值

變量 > 邊界值

變量 >= 邊界值

如 i>10 i< 10   i>=10 i>10 等等

最后一條語句i++可以有以下9種寫法之一

  1. i++ 
  2. ++i 
  3. i-- 
  4. --i 
  5. i += inc 
  6. -inc 
  7. ii = i + inc 
  8. i = inc + i 
  9. ii = i –inc 

例如i += 2; i -= 2;i = i + 2;i = i - 2;都是符合規范的寫法。

5.sections和section指令的用法

section語句是用在sections語句里用來將sections語句里的代碼劃分成幾個不同的段,每段都并行執行。用法如下:

  1. #pragma omp [parallel] sections [子句] 
  2.    #pragma omp section 
  3.    { 
  4.             代碼塊 
  5.    }  

先看一下以下的例子代碼:

  1. void main(int argc, char *argv) 
  2. #pragma omp parallel sections { 
  3. #pragma omp section 
  4.     printf(“section 1 ThreadId = %d/n”, omp_get_thread_num()); 
  5. #pragma omp section 
  6.     printf(“section 2 ThreadId = %d/n”, omp_get_thread_num()); 
  7. #pragma omp section 
  8.     printf(“section 3 ThreadId = %d/n”, omp_get_thread_num()); 
  9. #pragma omp section 
  10.     printf(“section 4 ThreadId = %d/n”, omp_get_thread_num()); 

執行后將打印出以下結果:

section 1 ThreadId = 0

section 2 ThreadId = 2

section 4 ThreadId = 3

section 3 ThreadId = 1

從結果中可以發現第4段代碼執行比第3段代碼早,說明各個section里的代碼都是并行執行的,并且各個section被分配到不同的線程執行。

使用section語句時,需要注意的是這種方式需要保證各個section里的代碼執行時間相差不大,否則某個section執行時間比其他section過長就達不到并行執行的效果了。

上面的代碼也可以改寫成以下形式:

  1. void main(int argc, char *argv) 
  2. #pragma omp parallel { 
  3. #pragma omp sections 
  4. #pragma omp section 
  5.        printf(“section 1 ThreadId = %d/n”, omp_get_thread_num()); 
  6. #pragma omp section 
  7.        printf(“section 2 ThreadId = %d/n”, omp_get_thread_num()); 
  8. #pragma omp sections 
  9.   
  10. #pragma omp section 
  11.        printf(“section 3 ThreadId = %d/n”, omp_get_thread_num()); 
  12. #pragma omp section 
  13.        printf(“section 4 ThreadId = %d/n”, omp_get_thread_num()); 

執行后將打印出以下結果:

section 1 ThreadId = 0

section 2 ThreadId = 3

section 3 ThreadId = 3

section 4 ThreadId = 1

這種方式和前面那種方式的區別是,兩個sections語句是串行執行的,即第二個sections語句里的代碼要等第一個sections語句里的代碼執行完后才能執行。

用for語句來分攤是由系統自動進行,只要每次循環間沒有時間上的差距,那么分攤是很均勻的,使用section來劃分線程是一種手工劃分線程的方式,最終并行性的好壞得依賴于程序員。

本篇文章中講的幾個OpenMP指令parallel, for, sections, section實際上都是用來如何創建線程的,這種創建線程的方式比起傳統調用創建線程函數創建線程要更方便,并且更高效。

當然,創建線程后,線程里的變量是共享的還是其他方式,主線程中定義的變量到了并行塊內后還是和傳統創建線程那種方式一樣的嗎?創建的線程是如何調度的?等等諸如此類的問題到下一篇文章中進行講解。

原文鏈接:http://blog.csdn.net/drzhouweiming/article/details/1175848

責任編輯:陳四芳 來源: blog.csdn.net
相關推薦

2013-12-16 16:49:57

OpenMP

2013-12-18 10:34:42

OpenMP線程

2011-11-17 10:34:44

并行程序

2011-07-05 15:59:57

面向對象編程

2010-12-24 10:23:50

程序員

2012-03-12 12:34:02

JavaF#

2013-12-12 16:30:20

Lua腳本語言

2009-12-04 10:53:06

VS WEB

2010-12-28 10:12:39

PHP

2010-06-03 19:28:02

Hadoop

2010-09-17 09:08:49

Java多線程

2017-09-05 08:16:29

代碼判斷函數

2009-12-25 16:36:45

WPF程序設計

2010-01-28 09:54:27

C++程序設計

2009-02-10 09:53:41

多線程程序設計Java

2011-08-05 15:46:32

Objective-C 程序設計

2010-09-25 13:47:14

Java跨平臺

2010-01-27 14:24:15

C++程序設計

2011-07-05 16:05:43

面向對象編程

2011-08-25 10:35:14

Lua語言函數
點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 成人免费在线视频 | 羞羞色视频 | 一区二区三区久久 | 欧美成年黄网站色视频 | 国产精品不卡 | 成人免费毛片在线观看 | 91观看| 国产精品久久国产精品 | 91原创视频在线观看 | 区一区二区三在线观看 | 亚洲传媒在线 | 久久久精品一区二区 | www.99热 | 国产三级一区二区 | 黄色片网站在线观看 | www.99久久.com| 国产午夜精品一区二区三区嫩草 | 免费在线观看毛片 | 亚洲三区在线观看 | 中文字幕在线观 | 麻豆国产一区二区三区四区 | 91在线观看视频 | 久久网日本 | 日韩免费视频 | 涩涩视频网 | 久久精品国产精品青草 | 国产精品久久久久无码av | 中文字幕一区二区三区不卡在线 | 91在线精品播放 | 免费国产精品久久久久久 | 欧美日韩在线电影 | 亚洲丝袜天堂 | 久草综合在线视频 | 红桃视频一区二区三区免费 | 欧美不卡在线 | 在线视频91| 国产免费一区二区 | 久久亚洲经典 | 毛片a级毛片免费播放100 | 欧美精品一区二区三区在线 | 亚洲激情视频在线 |