Transcript Document

多核结构与程序设计
多核结构与程序设计
杨全胜
http://www.njyangqs.com/
东南大学成贤学院计算机系
Southeast University
东 南 大 学
1
http://www.njyangqs.com/
多核结构与程序设计
使用OpenMP编程

内容
 什么是OpenMP?
 并行区域
 循环并行化
 数据作用域与保护数据
 明确的同步
 调度子句
 其他有用的结构和子句
Southeast University
东 南 大 学
2
http://www.njyangqs.com/
多核结构与程序设计
什么是OpenMP





OpenMP-Open specifications for Mulit
Processing-用于多线程程序开发的API
一种面向共享内存以及分布式共享内存的多处理器
多线程并行编程语言。
一种能够被用于显式指导多线程、共享内存并行的
应用程序编程接口(API)。
OpenMP具有良好的可移植性,支持多种编程语言
OpenMP能够支持多种平台,包括大多数的类UNIX
系统以及Windows NT系统(Windows 2000,
Windows XP,Windows Vista等)。
Southeast University
东 南 大 学
3
http://www.njyangqs.com/
多核结构与程序设计
什么是OpenMP






提供一组针对多线程程序设计的编译指导——数据嵌
入到源代码中
容易创建线程的Fortran和C/C++代码
支持数据并行模型
将串行的程序逐步地改造成一个并行程序,达到增
量更新程序的目的,减少程序编写人员一定的负担
支持粗粒度和细粒度并行
支持和标准化循环级并行
Southeast University
东 南 大 学
4
http://www.njyangqs.com/
多核结构与程序设计
什么是OpenMP
C$OMP FLUSH
#pragma omp critical
CALL OMP_SET_NUM_THREADS(10)
C$OMP THREADPRIVATE(/ABC/)
call omp_test_lock(jlok)
C$OMP parallel do shared(a, b, c)
C$OMP MASTER
call OMP_INIT_LOCK (ilok)
C$OMP ATOMIC
C$OMP
http://www.openmp.org
SINGLE PRIVATE(X)
setenv OMP_SCHEDULE “dynamic”
C$OMP PARALLEL DO ORDERED PRIVATE (A, B, C)
Current spec is OpenMP 3.1
C$OMP PARALLEL
(combined C/C++ and Fortran)
C$OMP
REDUCTION (+: A, B)
#pragma omp parallel for private(A, B)
Nthrds = OMP_GET_NUM_PROCS()
东 南 大 学
SECTIONS
!$OMP
C$OMP PARALLEL COPYIN(/blk/)
Southeast University
C$OMP ORDERED
BARRIER
C$OMP DO lastprivate(XX)
omp_set_lock(lck)
5
http://www.njyangqs.com/
多核结构与程序设计
什么是OpenMP

OpenMP* 结构
 Fork-join模型
 循环并行化
 数据环境构造
 同步构造
 众多的用于更好控制的应用程序接口API
Southeast University
东 南 大 学
6
http://www.njyangqs.com/
多核结构与程序设计
什么是OpenMP

编程模型
 Fork-join并行性:
 主线程根据需要产生一组线程
 并行性是逐步添加的:
串行程序逐渐发展成并行程
序
Fork-Join Model
Master
Thread
Southeast University
东 南 大 学
F
J
F
J
O
O
O
O
R
I
R
I
K
N
K
N
Parallel
Regions
7
http://www.njyangqs.com/
多核结构与程序设计
什么是OpenMP

OpenMP* 编译指导语法
 OpenMP*中很多结构是由编译指导语句
pragmas引起的具有OpenMP语义的语句.
 对C和C++,
编译指导的形式如下:
#pragma omp construct [clause [clause]…]
Southeast University
东 南 大 学
8
http://www.njyangqs.com/
什么是OpenMP

多核结构与程序设计
运行时库函数
 OpenMP运行时函数库原本用以设置和获取执行
环境相关的信息,它们当中也包含一系列用以同
步的API。
 要使用运行库函数所包含的函数,需在源程序中包
含头文件omp.h
• omp_get_thread_num(void)
• omp_get_num_thread(void)
 支持运行时对并行环境的改变和优化,给编程人
员足够的灵活性来控制运行时的程序运行状况。
 不同的平台提供不同的运行函数库
Southeast University
东 南 大 学
 Windows提供动态链接库 9
http://www.njyangqs.com/
举例: Hello Worlds
多核结构与程序设计
#include “stdafx.h”
#include “omp.h”
int _tmain (int argc, _TCHAR* argv[])
{
printf(“Hello from serial.\n”);
printf (“Thread number = %d\n”,omp_get_thread_num()); //串行执行
#pragma omp parallel
//开始并行执行
{
printf(“Hello from parallel. Thread
number=%d\n”,omp_get_thread_num());
}
printf (“Hello from serial again.\n”);
return 0;
}
Southeast University
东 南 大 学
10
http://www.njyangqs.com/
多核结构与程序设计
使用OpenMP编程

内容
 什么是OpenMP?
 并行区域
 循环并行化
 数据作用域与保护数据
 明确的同步
 调度子句
 其他有用的结构和子句
Southeast University
东 南 大 学
11
http://www.njyangqs.com/
多核结构与程序设计
并行区域




主线程
定义了构造代码块的并行区域
线程被作为交叉的并行pragma
而创建。
线程在区域的最后被阻塞
除非另外指定,数据在线程间
共享
#pragma omp parallel
Thread
1
Thread
2
Thread
3
隐含的栅障
主线程
C/C++中的并行区域定义 :
#pragma omp parallel
{
block
}
Southeast University
东 南 大 学
12
http://www.njyangqs.com/
多核结构与程序设计
并行区域

使用多少线程
 设置环境变量来决定使用的线程数
set OMP_NUM_THREADS=4
 这个变量并没有标准的缺省值
 很多系统:
• # of threads = # of processors
• Intel® 的编译器用这个做缺省
Southeast University
东 南 大 学
13
http://www.njyangqs.com/
多核结构与程序设计
使用OpenMP编程

内容
 什么是OpenMP?
 并行区域
 循环并行化
 数据作用域与保护数据
 明确的同步
 调度子句
 其他有用的结构和子句
Southeast University
东 南 大 学
14
http://www.njyangqs.com/
多核结构与程序设计
循环并行化

管理线程
#pragma omp parallel
#pragma omp for
for (i=0;i<N;i++){
Do_Work(I);
}
 将循环迭代拆分到多个线程中
 黄色部分必须在并行区域中
 OMP语句必须先于循环
Southeast University
东 南 大 学
15
http://www.njyangqs.com/
多核结构与程序设计
循环并行化

循环并行化语句的限制
 循环并行化的语句必须具有如下的形式
for (index = start ; index < end ; increment_expr)
 循环语句块应该是单出口与单入口的
 循环变量必须是有符号整型数
 循环语句中的比较操作只能是<, <=,>,>=
 循环变量每次迭代必须是有效靠近循环结束目标的
 循环的步长必须是整数加或整数减,加、减的数值
必须是一个循环不变量。
Southeast University
东 南 大 学
16
http://www.njyangqs.com/
多核结构与程序设计
循环并行化
#pragma omp parallel
#pragma omp for
for(i = 1, i < 13, i++)
c[i] = a[i] + b[i]


#pragma omp parallel
#pragma omp for
线程被分配一组独立的迭代
线程必须在并行区域结尾等
待(栅障)
Southeast University
东 南 大 学
i=1
i=5
i=9
i=2
i=6
i = 10
i=3
i=7
i = 11
i=4
i=8
i = 12
隐含的栅障
17
http://www.njyangqs.com/
多核结构与程序设计
循环并行化

组合pragmas
 这两个代码段是等价的
#pragma omp parallel
{
#pragma omp for
for (i=0;i< MAX; i++) {
res[i] = huge();
}
}
#pragma omp parallel for
for (i=0;i< MAX; i++) {
res[i] = huge();
}
Southeast University
东 南 大 学
18
http://www.njyangqs.com/
循环并行化

多核结构与程序设计
循环并行化语句的限制
 循环嵌套
 循环并行化编译指导语句可以加在任意一个循环之
前,则对应的最近的循环语句被并行化,其它部分
保持不变。
#pragma omp parallel for private(j)
for (i=0;i< MAX; i++)
for (j=0;j< MAX; j++ {
printf(“i=%d,j=%d”,i,j);
}
Southeast University
东 南 大 学
for (i=0;i< MAX; i++)
#pragma omp parallel for private(j)
for (j=0;j< MAX; j++ {
printf(“i=%d,j=%d”,i,j);
}
19
http://www.njyangqs.com/
多核结构与程序设计
使用OpenMP编程

内容
 什么是OpenMP?
 并行区域
 循环并行化
 数据作用域与保护数据
 明确的同步
 调度子句
 其他有用的结构和子句
Southeast University
东 南 大 学
20
http://www.njyangqs.com/
数据作用域和保护数据

线程1堆栈
数据环境
线程2堆栈
 OpenMP


使用共享存储程序设计模型
大多数变量默认为共享的.
堆
全局变量在线程间共享
• C/C++: 文件域变量, 静态
 但,
多核结构与程序设计
代码段
不是每一个变量都是共享的
 在并行区域中被调用的函数中的栈变量(参数和局部变
量)是私有的( PRIVATE)
 循环变量是私有的
• C/C+: 在嵌套循环的第一层循环的循环变量跟着:
#pragma omp for
Southeast University
东 南 大 学
21
http://www.njyangqs.com/
多核结构与程序设计
数据作用域和保护数据

数据作用域属性
 缺省的状态能被修改
default (shared | none)
 数据作用域属性支持下列两个子句
 设置作用域为共享的变量
shared(varname,…)
 设置作用域为私有的变量
private(varname,…)
Southeast University
东 南 大 学
22
http://www.njyangqs.com/
数据作用域和保护数据

多核结构与程序设计
私有子句
 为每个线程复制变量
C++ 对象按缺省构造
 任何外部值在并行区域是不确定的
 变量未初始化;
void* work(float* c, int N) {
float x, y; int i;
#pragma omp parallel for private(x,y)
for(i=0; i<N; i++) {
x = a[i]; y = b[i];
c[i] = x + y;
}
}
Southeast University
东 南 大 学
23
http://www.njyangqs.com/
多核结构与程序设计
数据作用域和保护数据

案例: 点积
float dot_prod(float* a, float* b, int N)
{
float sum = 0.0;
#pragma omp parallel for shared(sum)
for(int i=0; i<N; i++) {
sum += a[i] * b[i];
}
return sum;
错了吗?
}
Southeast University
东 南 大 学
24
http://www.njyangqs.com/
多核结构与程序设计
数据作用域和保护数据

保护共享数据
 必须保护可更改的共享数据的访问
float dot_prod(float* a, float* b, int N)
{
float sum = 0.0;
#pragma omp parallel for shared(sum)
for(int i=0; i<N; i++) {
#pragma omp critical
sum += a[i] * b[i];
}
return sum;
}
Southeast University
东 南 大 学
25
http://www.njyangqs.com/
多核结构与程序设计
使用OpenMP编程

内容
 什么是OpenMP?
 并行区域
 循环并行化
 数据作用域与保护数据
 明确的同步
 调度子句
 其他有用的结构和子句
Southeast University
东 南 大 学
26
http://www.njyangqs.com/
多核结构与程序设计
明确的同步

OpenMP* 临界结构
#pragma omp critical [(lock_name)]
 在一个结构块中定义一个临界区
线程等待它们的轮次—在一个
时刻,只有一个可以调用
consum() 因此在竞争条件中
保护了R1和R2
命名临界结构是可选的,但是
会提高性能
Southeast University
东 南 大 学
float R1,R2;
#pragma omp parallel
{ float B;
#pragma omp for
for(int i=0; i<niters; i++){
B = big_job(i);
#pragma omp critical (R1_lock)
consum (B, &R1);
A = bigger_job(i)
#pragma omp critical (R2_lock)
consum (A, &R2);
}
}
27
http://www.njyangqs.com/
多核结构与程序设计
明确的同步

OpenMP* 归约子句
reduction (op : list)
 在“list”中的变量在封闭的并行区域中必须是共
享的。
 在并行或循环并行化中:
 每个list变量的一个PRIVATE(私有)拷贝被创
建并且根据“op”操作来初始化
 这些拷贝被线程在局部范围内被修改
 在结构的最后,局部拷贝通过“op”运算被组合
成一个值并且和原始的SHARED(共享)变量相
组合。
Southeast University
东 南 大 学
28
http://www.njyangqs.com/
多核结构与程序设计
明确的同步

归约举例
#pragma omp parallel for reduction(+:sum)
for(i=0; i<N; i++) {
sum += a[i] * b[i];
}
 sum在每个线程的局部拷贝
 所有sum
的局部拷贝加到一起,并存储到“全局”
变量中
Southeast University
东 南 大 学
29
http://www.njyangqs.com/
多核结构与程序设计
明确的同步

C/C++ 归约操作
 一系列关联操作能被用作归约
 初始值是有算术意义的值
Operand
+
Initial Value
0
Operand
&
Initial Value
~0
*
1
|
0
-
0
&&
1
^
0
||
0
Southeast University
东 南 大 学
30
http://www.njyangqs.com/
多核结构与程序设计
数值积分例子
1
4.0

4.04.0
f(x) = 2 dx =static
long num_steps=100000; double

2
(1+x
) )
(1+x
step, pi;
0
void main()
{ int i;
double x, sum = 0.0;
2.0
0.0
X
step = 1.0/(double) num_steps;
for (i=0; i< num_steps; i++){
x = (i+0.5)*step;
sum = sum + 4.0/(1.0 + x*x);
}
pi = step * sum;
printf(“Pi = %f\n”,pi);
1.0
}
Southeast University
东 南 大 学
31
http://www.njyangqs.com/
多核结构与程序设计
实践2 – 计算π
static long num_steps=1000000;
double step, pi;
void main()
{ int i;
double x, sum = 0.0;
step = 1.0/(double) num_steps;
for (i=0; i< num_steps; i++){
x = (i+0.5)*step;
sum = sum + 4.0/(1.0 + x*x);
}
pi = step * sum;
printf("Pi = %12.9f\n",pi);
使用OpenMP的并行数字
集成代码
什么变量可以是共享的?
什么变量需要时私有的?
什么变量能够做归约运算?
}
Southeast University
东 南 大 学
32
http://www.njyangqs.com/
多核结构与程序设计
实践2 – 计算π
static long num_steps=1000000;
double step, pi;
void main()
{ int i;
double x, sum = 0.0;
step = 1.0/(double) num_steps;
#pragma omp parallel for private(x) reduction(+:sum)
for (i=0; i< num_steps; i++){
x = (i+0.5)*step;
sum = sum + 4.0/(1.0 + x*x);
}
pi = step * sum;
printf("Pi = %12.9f\n",pi);
}
Southeast University
东 南 大 学
33
http://www.njyangqs.com/
实践3-蒙托卡罗法求π

多核结构与程序设计
实验: 用蒙特卡罗法计算π
 根据圆面积公式,S=πr2
 看一个单位圆,其中,1/4个
1
x
单位圆的面积是单位矩形面积
y
的一部分,单位矩形面积为1,
-1
1
现在在单位矩形内产生大量
0
随机的点,则落在1/4圆内的
点所占的百分比就是1/4的单位
圆面积。
-1
 一个点是否在1/4单位圆内的判断方法就是该点的
坐标是否满足 x2+y2≤1
Southeast University
东 南 大 学
34
http://www.njyangqs.com/
实践3-蒙托卡罗法求π
多核结构与程序设计
unsigned int iter=200000000;
 int i,j;
double x, y;
double dUnderCurve=0.0;
double pi=0.0;
1
double r[BLOCK_SIZE*2];
x
VSLStreamStatePtr stream;
vslNewStream( &stream, BRNG, (int) clock() );
y
for(j=0;j<iter/BLOCK_SIZE; j++) {
-1
1
vdRngUniform( METHOD, stream, BLOCK_SIZE*2, r, 0.0, 1.0 );
0
for (i=0; i<BLOCK_SIZE; i++) {
x=r[i];
y=r[i+BLOCK_SIZE];
if (x*x + y*y <= 1.0) {
dUnderCurve++;
-1
}
}
}
vslDeleteStream( &stream );
Southeast University
35
pi = dUnderCurve / (double) iter * 4 ;
http://www.njyangqs.com/
东 南 大 学
实验: 用蒙特卡罗法计算π
实践3-蒙托卡罗法求π
多核结构与程序设计
unsigned int iter=200000000;
int i,j;
double x, y;
double dUnderCurve=0.0;
double pi=0.0;
实验: 用蒙特卡罗法计算π
#pragma omp parallel private(stream,x,y,i) reduction(+:dUnderCurve)
double r[BLOCK_SIZE*2];
1
VSLStreamStatePtr stream;
x
vslNewStream( &stream, BRNG, (int) clock() );
#pragma omp for
y
for(j=0;j<iter/BLOCK_SIZE; j++) {
-1
1
vdRngUniform( METHOD, stream, BLOCK_SIZE*2,
r, 0.0, 1.0 );
for (i=0; i<BLOCK_SIZE; i++) {
0
x=r[i];
y=r[i+BLOCK_SIZE];
if (x*x + y*y <= 1.0) {
dUnderCurve++;
-1
}
}
}
vslDeleteStream( &stream );
Southeast
piUniversity
= dUnderCurve / (double) iter * 4 ;
36
http://www.njyangqs.com/
东 南 大 学
多核结构与程序设计
去除同步,减少开销

看下面的程序:
float dot_prod(float* a, float* b, int N)
{
float sum = 0.0;
#pragma omp parallel for shared(sum)
for(int i=0; i<N; i++) {
#pragma omp critical
sum += a[i] * b[i];
}
return sum;
}
Southeast University
东 南 大 学
37
http://www.njyangqs.com/
多核结构与程序设计
去除同步,减少开销

计算的开始与结束迭代:
float dot_prod(float* a, float* b, int N)
{ float sum = 0.0, lsum[10];
int Ncore = omp_get_num_procs ();
int nstep=N/Ncore;
#pragma omp parallel for
for (k=0;k<Ncore;k++)
for(int i=k*nstep; i<(k+1)*nstep; i++) {
lsum[k] += a[i] * b[i];
}
for (i=0;i<Ncore;i++)
sum+=lsun[i];
return sum;
Southeast University
}
38
http://www.njyangqs.com/
东 南 大 学
多核结构与程序设计
使用OpenMP编程

内容
 什么是OpenMP?
 并行区域
 循环并行化
 数据作用域与保护数据
 明确的同步
 调度子句
 其他有用的结构和子句
Southeast University
东 南 大 学
39
http://www.njyangqs.com/
多核结构与程序设计
调度子句

负载均衡问题
 看下面的程序
int i, j;
Int a[100][100];
for (i=0; i<100;i++)
{
for (j=0; j<100;j++)
{
a[i][j]=i*j;
}
}
Southeast University
东 南 大 学
40
http://www.njyangqs.com/
多核结构与程序设计
调度子句

任务调度
 多线程程序中,要实现较好地负载平衡而获得最
优性能,就必须对循环进行高效的调度。
 调度的目的是使得每个线程都处于忙的状态,而
不至于有的忙有的闲。
 采取的办法是合理分配数据和任务到线程。
Southeast University
东 南 大 学
41
http://www.njyangqs.com/
多核结构与程序设计
调度子句

调度子句
#pragma omp parallel for schedule(kind[, chunksize])
 kind参数有四种类型
 static,dynamic,guided,runtime
 chunksize参数(可选)
 表示循环迭代次数,该参数必须是整数。
 kind是runtime时,不能有chunksize
Southeast University
东 南 大 学
42
http://www.njyangqs.com/
多核结构与程序设计
调度子句

可用的调度
调度类型
描
述
假设有n次循环迭代,m个线程,那么每个线程静态
Static
分配n/m次迭代,如果n/m不为整数,则实际迭代
(缺省类型) 次数可能相差一个chunksize
guided
使用一个内部任务队列,当某个线程可用时,为其
分配chunksize数量的循环迭代。线程完成这一组
迭代后,再到任务队列取下一组迭代。
与dynamic类似,但迭代次数刚开始比较大,后来
迭代次数会按指数级下降到chunksize大小。
runtime
在运行时使用OMP_SHEDULE环境变量来确定使
用上述哪种调度类型。
dynamic
Southeast University
东 南 大 学
43
http://www.njyangqs.com/
多核结构与程序设计
调度子句

调度子句举例
#pragma omp parallel for schedule(static)
for(i = 1; i <= 12; i++ ) {
a[i]=factorial(i);
}
 迭代被划分,其中缺省的chunksize为1
 如果线程数是2,则
• 线程 0计算i=1,2,3,4,5,6的情况
• 线程1计算i=7,8,9,10,11,12的情况
Southeast University
东 南 大 学
44
http://www.njyangqs.com/
多核结构与程序设计
调度子句

调度子句举例
#pragma omp parallel for schedule(static,3)
for(i = 1; i <= 12; i++ ) {
a[i]=factorial(i);
}
 迭代被划分,其中chunksize为3
 如果线程数是2,则
• 线程 0计算i=1,2,3,7,8,9的情况
• 线程1计算i=4,5,6,10,11,12的情况
Southeast University
东 南 大 学
45
http://www.njyangqs.com/
多核结构与程序设计
调度子句

调度子句举例
#pragma omp parallel for schedule(dynamic,3)
for(i = 1; i <= 12; i++ ) {
a[i]=factorial(i);
}
 迭代被划分,其中chunksize为3
 如果线程数是2,则
• 线程 0计算i=4,5,6,7,8,9的情况
• 线程1计算i=1,2,3,10,11,12的情况
Southeast University
东 南 大 学
46
http://www.njyangqs.com/
多核结构与程序设计
调度子句

调度子句举例
#pragma omp parallel for schedule(guided,3)
for(i = 1; i <= 12; i++ ) {
a[i]=factorial(i);
}
 迭代被划分,其中chunksize为3
 如果线程数是2,则
• 线程 0计算i=1,2,3,4,5,10,11,12的情况
• 线程1计算i=6,7,8,9的情况
Southeast University
东 南 大 学
47
http://www.njyangqs.com/
多核结构与程序设计
使用OpenMP编程

内容
 什么是OpenMP?
 并行区域
 循环并行化
 数据作用域与保护数据
 明确的同步
 调度子句
 其他有用的结构和子句
Southeast University
东 南 大 学
48
http://www.njyangqs.com/
其它有用的结构与子句

多核结构与程序设计
并行部分(sections和section子句
 代码可并行执行的独立部分
#pragma omp parallel sections
{
#pragma omp section
phase1();
#pragma omp section
phase2();
#pragma omp section
phase3();
}
Southeast University
东 南 大 学
49
串行
并行
http://www.njyangqs.com/
其它有用的结构与子句

多核结构与程序设计
Single结构
 被标注的代码块只能被一个线程执行
 选择第一个到达的线程
 在尾部隐含栅障
#pragma omp parallel
{
DoManyThings();
#pragma omp single
{
ExchangeBoundaries();
}
// 其他线程都在这里等待
DoManyMoreThings();
}
Southeast University
东 南 大 学
50
http://www.njyangqs.com/
多核结构与程序设计
其它有用的结构与子句

Master结构
 被标注的代码块只能被主线程执行
 在尾部没有隐含的栅障
#pragma omp parallel
{
DoManyThings();
#pragma omp master
{
ExchangeBoundaries();
}
DoManyMoreThings();
}
Southeast University
东 南 大 学
51
http://www.njyangqs.com/
多核结构与程序设计
其它有用的结构与子句

隐含的栅障
 多个OpenMP*
结构有隐含的栅障
 parallel
 for
 single
 不必要的栅障会损坏性能
 等待的线程啥事都做不了!
 安全的情况下,用nowait子句撤销隐含的栅障
Southeast University
东 南 大 学
52
http://www.njyangqs.com/
其它有用的结构与子句

多核结构与程序设计
Nowait子句
Nowait子句的文法有助于阻止隐含的栅障:
#pragma omp for nowait
for(…)
{…};
#pragma omp single nowait
{ […] }
当线程需要在独立的计算间等待的时候使用
#pragma omp for schedule (dynamic, 1) nowait
for(int i=0; i<n; i++)
a[i] = bigFunc1(i);
#pragma omp for schedule (dynamic, 1)
for(int j=0; j<m; j++)
b[j] = bigFunc2(j);
Southeast University
东 南 大 学
53
http://www.njyangqs.com/
多核结构与程序设计
其它有用的结构与子句

Barrier结构
 明确的栅障同步
 每个线程都要等待直到所有线程到达
#pragma omp parallel shared (A, B, C)
{
DoSomeWork(A,B);
printf(“Processed A into B\n”);
#pragma omp barrier
DoSomeWork(B,C);
printf(“Processed B into C\n”);
}
Southeast University
东 南 大 学
54
http://www.njyangqs.com/
其它有用的结构与子句

多核结构与程序设计
Atomic结构
 Atomic结构创建了一个小的临界区域,该临界
区大多在一些处理器中是用一条指令或者很少
的几条指令完成的。因为它小,所以执行起来
比临界段要块。其语法如下:
#pragma omp parallel for shared(x, y, index, n)
for (i = 0; i < n; i++) {
#pragma omp atomic
x[index[i]] += work1(i);
y[i] += work2(i);
}
Southeast University
东 南 大 学
55
http://www.njyangqs.com/
多核结构与程序设计
其它有用的结构与子句

OpenMP* API
 获取一个执行队列中的线程号
int omp_get_thread_num(void)
 获取一个执行队列中的线程数
int omp_get_num_thread (void)
 获取处理器(核)数
int omp_get_num_procs (void)
 通常不需要专门的OpenMP代码,否则:
 会导致代码的不连续一致性
 除非确实有特殊用途(debugging)
 但必须包含一个头文件
Southeast University
东 南 大 学
#include <omp.h>
56
http://www.njyangqs.com/
多核结构与程序设计
小结

OpenMP* 是:
 是一种简单的为共享存储模式使用的并行编程模

型。
我们探讨了在OpenMP编码中如何:
 建立并行的代码区域(omp parallel)
 划分工作(omp for)
 变量分类(omp private….)
 同步(omp critical…)
 调度(omp schedule…)
Southeast University
东 南 大 学
57
http://www.njyangqs.com/
多核结构与程序设计
进一步的话题
Southeast University
东 南 大 学
58
http://www.njyangqs.com/
多核结构与程序设计
更多关于OpenMP*

数据环境结构
 FIRSTPRIVATE
 LASTPRIVATE
 THREADPRIVATE
Southeast University
东 南 大 学
59
http://www.njyangqs.com/
多核结构与程序设计
Firstprivate子句


该私有变量的初始值来自同名共享变量
C++对象是拷贝构造
incr=30;
#pragma omp parallel for firstprivate(incr)
for (I=0;I<=MAX;I++) {
if ((I%2)==0) incr++;
A(I)=incr;
}
Southeast University
东 南 大 学
60
http://www.njyangqs.com/
多核结构与程序设计
Lastprivate子句


私有变量将最后一次迭代的值赋给同名的共享变量
C++对象就像被指派那样被修改
void sq2(int n, double *lastterm)
{
double x; int i;
#pragma omp parallel
#pragma omp for lastprivate(x)
for (i = 0; i < n; i++){
x = a[i]*a[i] + b[i]*b[i];
b[i] = sqrt(x);
}
lastterm = x;
}
Southeast University
东 南 大 学
61
http://www.njyangqs.com/
多核结构与程序设计
Threadprivate子句


使用threadprivate子句用来标明某一个全局变量是线程
私有数据,在程序运行的过程中,不能被其他线程访问。
使用copyin子句对线程私有的全局变量进行初始化。
struct Astruct A;
#pragma omp threadprivate(A)
…
Private copies of “A”
persist between
regions
#pragma omp parallel
copyin(A)
do_something_to(&A);
…
#pragma omp parallel
do_something_else_to(&A);
Southeast University
东 南 大 学
62
http://www.njyangqs.com/