http://blog.csdn.net/bendanban/article/details/6303282
在上一節(jié)中我們講的是一個(gè)常用的并行化編程方法(for的并行化),其實(shí)它只是并行化編程的一個(gè)特例,只是它的地位較高,或者說(shuō)它比其它并行化更重要。在本節(jié)中我們將討論一般的并行區(qū)域編程。
并行區(qū)域的編譯指導(dǎo)語(yǔ)句一般格式
一般格式:#pragma omp parallel [clause[clause]…]{…}
其中{…}中為每個(gè)線程都執(zhí)行的部分,在parallel后面可以跟隨一些指導(dǎo)子句,例如:threadprivate、copyin等,本節(jié)中將以一些實(shí)例來(lái)依次講解這些語(yǔ)句的作用。
時(shí)刻記住,主線程就是0號(hào)線程,這個(gè)與for不同,另外private、firstprivate、lastprivate是for并行的東西最好不要拿來(lái)比較,盡管我在本文里比較了,但是我還是感覺(jué)有些頭痛啊。
例子實(shí)例
例1 不帶指導(dǎo)子句的并行程序
#pragma omp parallel指示它下面的一對(duì)大括號(hào)內(nèi)的程序復(fù)制執(zhí)行threads個(gè)數(shù)次。默默人情況下,所有并行區(qū)域中的變量是共享的,所以一定要謹(jǐn)防數(shù)據(jù)競(jìng)爭(zhēng)的發(fā)生。
#include
#include "omp.h"
int main(int argc, char* argv[])


{
#pragma omp parallel
for (int i = 0; i < 2; i++)

{
printf("Hello World! i = %d, Thread Num = %d/n", i, omp_get_thread_num());
}
return 0;
}

圖1、例1的執(zhí)行結(jié)果
例1的執(zhí)行結(jié)果可以看出四個(gè)線程分別執(zhí)行了一遍#pragma omp parallel下面的語(yǔ)句,想想一下如果使用#pragma omp parallel for會(huì)是什么樣的結(jié)果。
例2 使用threadprivate子句
此命令表示所有并行線程使用指定變量為各自私有的,能被定義為各線程私有變量的變量只能是靜態(tài)變量和全局變量。看下面的程序,希望你能發(fā)現(xiàn),其實(shí)#pragma omp threadprivate()是可以單獨(dú)使用的。
說(shuō)明一下:被定義為threadprivate的變量對(duì)于每個(gè)線程永遠(yuǎn)是活的,你在任何時(shí)候再次重新啟動(dòng)各線程時(shí),前面并行時(shí)最后得到的變量值仍然保留他的值,如果你用private代替threadprivate,那么你重新啟動(dòng)各線程時(shí),變量的值仍然為0。如果你不初始化要聲明為private的變量,那么在串行程序中,你就不能再?zèng)]有任何賦值的情況下使用它,否則會(huì)引起異常的(VS2010)。而且private不能單獨(dú)像threadprivate那樣定義某個(gè)變量。
如果你使用另外#pragma omp threadprivate(var),那么var必須是靜態(tài)變量或者全局變量,如過(guò)你在并行開(kāi)始之前并沒(méi)有初始化賦值,那么每個(gè)線程中默認(rèn)var的值為0.如果你賦了初值,那么每個(gè)線程中var的初值都是你賦的初始值。其中主線程就是0號(hào)線程。如果你使用了#pragma omp private(var),那么var并不會(huì)賦初值,即使你在并行之前賦了初值。想想原先#pragma omp parallel for 的firstprivate就知道了,呵呵。在#pragma omp parallel中可以使用lastprivate,但是不能使用lastprivate,使用firstprivate(var)后,串行部分的var并不是并行時(shí)0號(hào)線程的var值,它仍未你原先賦的初值。是不是很繞啊?呵呵,你可以這樣理解,使用firstprivate和private的并行都不是純真的聯(lián)合主線程的編號(hào)。這樣就混不了了。
#include
#include "omp.h"
int sum = 0;
#pragma omp threadprivate(sum)
int main(int argc, char* argv[])


{
#pragma omp parallel

{
sum += omp_get_thread_num();
printf("parallel sum = %d; thread num = %d/n", sum, omp_get_thread_num());
}
printf("/nserial sum = %d; thread num = %d/n/n", sum, omp_get_thread_num());
#pragma omp parallel
printf("parallel sum = %d; thread num = %d/n", sum, omp_get_thread_num());
return 0;
}

圖2、例2執(zhí)行結(jié)果
threadprivate指定了sum這個(gè)變量屬于每個(gè)線程,每個(gè)線程都有自己的sum變量,各個(gè)線程結(jié)束后他們的sum變量并沒(méi)有注銷(xiāo),在此啊執(zhí)行時(shí),他們各自的sum值還保持原值。
例3 使用copyin
指定主線程的值拷貝到各線程中去,下面的例子中,sum是每個(gè)線程獨(dú)有的,并且初始值都是0,main中第一行代碼將0號(hào)線程的sum值賦為100,其它線程的sum值并沒(méi)有變。
#include <stdio.h>
#include "omp.h"
int sum;
#pragma omp threadprivate(sum)
int main(int argc, char* argv[])


{
sum = 100;
#pragma omp parallel copyin(sum)

{
sum += omp_get_thread_num();
printf("parallel sum = %d; thread num = %d/n", sum, omp_get_thread_num());
}
printf("/nserial sum = %d; thread num = %d/n/n", sum, omp_get_thread_num());
#pragma omp parallel
printf("parallel sum = %d; thread num = %d/n", sum, omp_get_thread_num());
return 0;
}

圖3、例3的執(zhí)行結(jié)果

圖4、例3中將copyin(sum)刪除后的執(zhí)行結(jié)果
通過(guò)以上圖3、4可以看出copyin的用處是初始化各個(gè)線程中自己私有的sum變量。實(shí)際上定義sum為全局量時(shí)的初始值就是原sum值(如果不使用copyin的話)。
我想了想threadprivate和private以及firstprivate的區(qū)別。寫(xiě)出來(lái)大家討論下。
1、threadprivate,限制變量為每個(gè)線程私有。被限制的變量必須具有全局特性,他的生命周期是整個(gè)程序。
2、private,可以限制變量為每個(gè)線程私有,但是他的生命周期是一次啟動(dòng)并行計(jì)算。
3、firstprivate,可以將穿行程序中的初值帶進(jìn)每個(gè)線程,變量為每個(gè)線程私有。生命周期與private相同。
4、還有個(gè)lastprivate的問(wèn)題,他并不能在區(qū)域并行中使用。
大家實(shí)驗(yàn)把。。。