簡易的程式平行化-OpenMP(三)範例 parallel、section

 

簡易的程式平行化-OpenMP(三)範例 parallel、section

OpenMP 裡,平行化的方式有三種:parallelsectionsfor(不過 section 和 for 都需要 parrallel)。這裡,舉些例子來說明他們的運作。

而用來測試的函式 Test內容如下

void Test( int n )
{
  printf( " - %d/n", , n );
}

 輸出的形式會是:thread_id> - n


parrallel

parrallel 的語法很直接,就是 #pragma omp parallel;不過原則上,後面要用 {} 來指定 scope。範例程式如下:

#include 
#include 
#include 

int main(int argc, char* argv[])
{
	#pragma omp parallel
	{
		Test( 0 );
	}
	system( "pause" );
}

而這樣的程式在一台雙核心的電腦上,結果應該會是:

 - 0
 - 0

從結果可以看出來,Test() 被兩個不同的 thread 個別執行了一次,所以會輸出兩行;這是因為 OpenMP 會根據硬體,自動選擇預設的執行緒數目。

接著,在針對程式些修改,變成

#include 
#include 
#include 
#define OMP 11

int main(int argc, char* argv[])
{
	#pragma omp parallel if(OMP>10) num_threads(3)
	{
		Test( 0 );
	}
	printf( "/n==========================/n/n" );
	system( "pause" );
}

而這樣的程式在一台雙核心的電腦上,結果應該會是:

 - 0
 - 0
 - 0

在程式中,加入了 ifnum_threads 這兩個語法。num_threads 是用來指定執行緒的數目的,而在上面的程式中,把它指定成 3,所以結果會由三個不同的 thread,個別呼叫一次 Test()

if(OMP>10) 則是拿來控制是否要平行化的條件;如果把 #define OMP 11 改成 #define OMP 9 (或者任何不大於 10 的數)的話,結果就會變成 Test() 只被呼叫一次,只印出一行。不過要注意的一點是,用 if 條件來停止平行化,實際上應該是將執行緒的數目設定成 1;也就是說 OpenMP 還是會做處理,但是會只用一個執行緒跑。而這樣使用要注意的就是,如果曾經有因為 if 而停止平行化的話,接下來的預設的執行緒數目也會變成 1!所以如果真的要用 if 來判斷是否要平行化,最好把接下來的部份,加上 num_threads 來指定執行緒的數目。下面是一個例子:

#pragma omp parallel
Test( 1 );
#pragma omp parallel if(false)
Test( 2 );
#pragma omp parallel
Test( 3 );

他的執行結果應該會是:

 - 1
 - 1
 - 2
 - 3

這是因為在執行 Test(1) 的時候,有被平行化成兩個 thread,所以被執行了兩次。但是到了 Test(2) 的時候,因為執行了 if(false),所以將平行化關閉、設定為一個 thread;同時這也導致了接下來的 Test(3) 也變成只以一個 thread 來進行。

而在 parallel 的範圍內,還有一些 directive 是可以使用的;像是 singlemaster 等等。像下面的程式

#pragma omp parallel num_threads(2)
{
	for( int i = 0; i < 3; ++ i )
		Test( i );
	printf( "Hi/n" );
	#pragma omp single
	{
		printf( "Hi, single/n" );
	}
	#pragma omp master
	printf( "Hi, master/n" );
}

執行結果:

 - 0
 - 0
 - 1
 - 1
 - 2
 - 2
Hi
Hi
Hi, single
Hi, master

其中,可以發現加上 singlemaster 的部份的程式只會被執行一次;而 mastersingle 兩者間的差異,則是 master 會一定由主執行緒來執行,single 不一定。

基本上,Heresy 不大確定什麼時候會直接用到 parrallel,所以也就不多加著墨了。(什麼時候會要把一般的程式多執行幾次啊? @@)


sections

sections 的用處,是把程式中沒有相關性的各個程式利用 #pragma omp section 來做區塊切割,然後由 OpenMP 做平行的處理。下面的程式是一個簡單的例子:

int main(int argc, char* argv[])
{
	#pragma omp parallel sections
	{
		#pragma omp section
		{
			for( int k = 0; k < 100000; ++ k )
			{}
			Test( 0 );
		}
		#pragma omp section
		{
			Test( 1 );
		}
		#pragma omp section
		{
			Test( 2 );
		}
		#pragma omp section
		{
			Test( 3 );
		}
	}
}

而執行出來的結果,則是:

 - 1
 - 2
 - 3
 - 0

從執行的輸出結果可以發現:由於 thread0 先執行了執行時間最久的第一個 section,而在 thread0 結束第一個 section 前,其他三個 section 已經由 thread1 執行結束了~

不過利用 sections 平行化的時候,要注意程式的相依性;如果兩段程式是有相關性的話,實際上並不適合用 sections 來做平行化。下面是個錯誤的例子:

int	a[5];
#pragma omp parallel sections
{
	#pragma omp section
	{
		int	k;
		for( int i = 0; i < 5; ++ i )
		{
			a[i] = i;
			for( k = 0; k < 10000; ++ k )
			{}
		}
	}
	#pragma omp section
	{
		for( int i = 0; i < 5; ++ i )
			printf( "%d/n", a[i] );
	}
}

其中,程式裡 for( k = 0; k < 10000; ++ k ){} 的目的只是在拖慢時間。輸出結果是:

0
1
-858993460
-858993460
-858993460

這是因為第一個 section 的部份,執行的速度比較慢,所以當第二的 section 要列印的時候,還來不及將資料填入 a[] 裡,所以會導致錯誤。


 目錄:

  • 簡易的程式平行化方法-OpenMP(一)簡介
  • 簡易的程式平行化-OpenMP(二)語法說明
  • 簡易的程式平行化-OpenMP(三)範例 parallel、section
  • 簡易的程式平行化-OpenMP(四) 範例 for
  • 簡易的程式平行化-OpenMP(五) 變數的平行化

參考資料:

  • MSDN 的 OpenMP:http://msdn2.microsoft.com/en-us/library/tt15eb9t.aspx

你可能感兴趣的:(parallel,thread,system)