clause
clause
clause
Create successful ePaper yourself
Turn your PDF publications into a flip-book with our unique Google optimized e-Paper software.
机 群 应 用 开 发<br />
并 行 编 程 原 理 及<br />
程 序 设 计<br />
Parallel Programming:<br />
Fundamentals and Implementation<br />
戴 荣<br />
dair@dawning.com.cn<br />
曙 光 信 息 产 业 有 限 公 司<br />
2006.4<br />
2006 年 4 月 共 享 存 储 编 程 1/108
参 考 文 献<br />
黄 铠 , 徐 志 伟 著 , 陆 鑫 达 等 译 . 可 扩 展 并 行 计 算 技 术 , 结 构 与 编 程 . 北 京 : 机<br />
械 工 业 出 版 社 , P.33~56,P.227~237, 2000.<br />
陈 国 良 著 . 并 行 计 算 — 结 构 、 算 法 、 编 程 . 北 京 : 高 等 教 育 出 版 社 ,1999.<br />
Barry Wilkinson and Michael Allen. Parallel Programming(Techniques<br />
and Applications using Networked Workstations and Parallel<br />
Computers). Prentice Hall, 1999.<br />
李 晓 梅 , 莫 则 尧 等 著 . 可 扩 展 并 行 算 法 的 设 计 与 分 析 . 北 京 : 国 防 工 业 出<br />
版 社 ,2000.<br />
张 宝 琳 , 谷 同 祥 等 著 . 数 值 并 行 计 算 原 理 与 方 法 . 北 京 : 国 防 工 业 出 版<br />
社 ,1999.<br />
都 志 辉 著 . 高 性 能 计 算 并 行 编 程 技 术 —MPI 并 行 程 序 设 计 . 北 京 : 清 华<br />
大 学 出 版 社 , 2001.<br />
2006 年 4 月 共 享 存 储 编 程 2/108
相 关 网 址<br />
MPI: http://ww.mpi-forum.org,<br />
http://www.mcs.anl.gov/mpi<br />
Pthreads: http://www.oreilly.com<br />
PVM: http://www.epm.ornl.gov/pvm/<br />
OpemMP: http://www.openmp.org<br />
网 上 搜 索 :www.google.com<br />
2006 年 4 月 共 享 存 储 编 程 3/108
共 享 存 储 编 程<br />
Programming with Shared<br />
Memory<br />
2006 年 4 月 共 享 存 储 编 程 4/108
共 享 存 储 并 行 机 模 型<br />
体 系 结 构 特 点 ::<br />
• 多 台 处 理 机 通 过 互 联 网 络 共 享 一 个<br />
统 一 的 内 存 空 间 ,, 通 过 单 一 内 存 地 址 来<br />
实 现 处 理 机 间 的 协 调 ..<br />
• 内 存 空 间 也 可 由 多 个 存 储 器 模 块 构<br />
成 ..<br />
• 每 台 处 理 机 可 以 执 行 相 同 或 不 同 的<br />
指 令 流 ,, 每 台 处 理 机 可 以 直 接 访 问 到 所<br />
有 数 据 ..<br />
• 处 理 机 间 通 信 是 借 助 于 共 享 主 存 来<br />
实 现 的 ..<br />
• 可 扩 展 性 差 ,, 当 处 理 机 需 要 同 时 访 问<br />
共 享 全 局 变 量 时 ,, 产 生 内 存 竞 争 现 象 而<br />
严 重 影 响 效 率 ,, 比 较 适 合 中 小 规 模 应 用<br />
问 题 的 计 算 和 事 务 处 理 ..<br />
2006 年 4 月 共 享 存 储 编 程 5/108
共 享 存 储 编 程 标 准 与 特 点<br />
共 享 存 储 器 编 程 标 准<br />
Pthreads( 线 程 标 准 )<br />
X3H5( 线 程 标 准 )<br />
OpenMP( 最 常 用 的 共 享 存 储 并 行 编 程 方 式 , 是 我 们 讨 论 的 重 点 .)<br />
共 享 存 储 器 编 程 特 点<br />
显 式 多 线 程 库 调 用 .(Pthreads).<br />
编 译 制 导 语 句 ,OpenMP 等 .<br />
语 言<br />
C,Fortran77,Fortran90/95,C++…<br />
2006 年 4 月 共 享 存 储 编 程 6/108
并 行 编 程 标 准<br />
线 程 库 标 准 (Thread Library)<br />
– Win32 API.<br />
– POSIX threads 线 程 模 型 .<br />
– X3H5: 概 念 性 线 程 模 型<br />
编 译 制 导 (Compiler Directives)<br />
– OpenMP - portable shared memory parallelism.<br />
2006 年 4 月 共 享 存 储 编 程 7/108
为 什 么 流 行 多 线 程 编 程 ?<br />
线 程 : 在 进 程 的 内 部 执 行 的 指 令 序 列 .<br />
相 对 于 进 程 , 线 程 开 销 小 :<br />
创 建 一 个 线 程 的 时 间 大 约 是 建 立 一 个 新 进 程 的 1/30。 如 在 Sun4/75 工 作<br />
上 站 上 , 创 建 一 个 非 绑 定 线 程 约 为 52 微 秒 , 而 fork() 一 次 的 时 间 为<br />
1700 微 秒 。<br />
线 程 同 步 时 间 约 是 进 程 同 步 时 间 的 1/3.<br />
线 程 与 RPC 相 结 合 , 发 挥 多 处 理 机 的 处 理 能 力 ;<br />
发 挥 多 处 理 器 的 处 理 能 力 ;<br />
开 发 程 序 的 并 发 性 , 改 善 程 序 的 结 构 .<br />
容 易 实 现 数 据 共 享 : 由 于 线 程 共 用 内 存 地 址 , 因 此 可 实 现 数 据 共 享<br />
例 : 一 高 性 能 Web 服 务 器 可 为 每 一 打 开 链 接 的 浏 览 器 分 配 一 个 线 程 , 所<br />
有 线 程 即 可 共 用 同 一 cache 来 访 问 网 站 的 热 点 话 题<br />
统 一 的 标 准 :<br />
以 前 各 开 发 商 提 供 互 不 兼 容 的 线 程 库 , 结 果 导 致 多 线 程 程 序 不 能 很 好 地<br />
移 值 。 自 1995 年 的 POSIX 线 程 标 准 实 施 之 后 , 极 大 地 促 进 多 线 程 编 程 的<br />
统 一 。 各 系 统 都 支 持 Pthreads, 如 Linux、SUN、IBM AIX 等 。<br />
2006 年 4 月 共 享 存 储 编 程 8/108
Pthreads 线 程 模 型<br />
POSIX1003.4a 小 组 研 究 多 线 程 编 程 标 准 . 当 标 准 完 成 后 , 大 多 数 支<br />
持 多 线 程 的 系 统 都 支 持 POSIX 接 口 . 很 好 的 改 善 了 多 线 程 编 程 的 可 移<br />
植 性 .<br />
IEEE Portable Operating System Interface, POSIX,<br />
1003.1-1995 标 准 :POSIX 线 程 模 型 :pthreads.<br />
2006 年 4 月 共 享 存 储 编 程 9/108
线 程 管 理 (Pthread<br />
为 例 )<br />
创 建 :pthread_create<br />
终 止 :pthread_exit<br />
汇 合 :pthread_join<br />
分 离 :pthread_detach<br />
线 程 属 性 初 始 化 :pthread_attr_init<br />
唯 一 执 行 :pthread_once<br />
2006 年 4 月 共 享 存 储 编 程 10/108
同 步 对 象<br />
在 共 享 存 储 多 处 理 器 并 行 机 上 , 线 程 通 过 全 局 变 量 通 信 ,<br />
对 于 全 局 变 量 的 操 作 必 须 进 行 同 步 。<br />
pthread 提 供 两 个 线 程 同 步 原 语 : 互 斥 和 条 件 变 量 .<br />
2006 年 4 月 共 享 存 储 编 程 11/108
互 斥 锁 函 数<br />
函 数<br />
Mutex_init()<br />
Mutext_lock()<br />
Mutex_trylock()<br />
Mutex_unlock()<br />
Mutex_destroy()<br />
操 作<br />
初 始 化 一 个 互 斥 锁<br />
阻 塞 式 加 锁 操 作<br />
非 阻 塞 式 加 锁 操 作<br />
解 锁<br />
解 除 互 斥 状 态<br />
2006 年 4 月 共 享 存 储 编 程 12/108
条 件 变 量 的 函 数<br />
函 数<br />
操 作<br />
pthread_cond_init() 初 始 化 条 件 变 量<br />
pthread_cond_wait() 阻 塞 直 至 条 件 为 真<br />
pthread_cond_signal() 强 制 条 件 为 真 , 解 除 等 待 条 件 的 线 程 的 阻 塞<br />
pthread_cond_timedwait() 阻 塞 直 到 指 定 条 件 为 真 或 timeout<br />
pthread_cond_broadcast() 解 除 所 有 等 待 条 件 的 线 程 的 阻 塞<br />
pthread_cond _destroy() 销 毁 条 件 变 量<br />
2006 年 4 月 共 享 存 储 编 程 13/108
Hello World(1)<br />
#include <br />
#include "stdio.h"<br />
void *worker();<br />
main()<br />
{<br />
pthread_t thread;<br />
pthread_create(&thread,NULL,worker,NULL);<br />
pthread_join(thread,NULL);<br />
}<br />
void *worker()<br />
{<br />
printf("Hello World!\n");<br />
}<br />
编 译 命 令<br />
gcc gcc hello.c –lpthread<br />
运 行 结 果<br />
Hello World!<br />
2006 年 4 月 共 享 存 储 编 程 14/108
pthread_t 线 程 数 据 类 型<br />
pthread_create(&thread,NULL,worker,NULL);<br />
函 数 pthread_create() 用 于 创 建 一 新 的 线 程 , 新 线 程 一 旦 建 立 便 进 入 运<br />
行 状 态<br />
参 数 :<br />
⌧ 线 程 指 针 或 句 柄<br />
⌧ 线 程 属 性 变 量 , 属 性 参 数 : 默 认 为 NULL. 属 性 对 象 一 旦 建 立 可 以 用 于<br />
创 建 多 个 具 有 共 同 属 性 的 线 程 , 线 程 创 建 后 , 可 删 除 属 性 对 象 .<br />
⌧ 线 程 要 执 行 的 函 数<br />
⌧ 传 入 该 执 行 函 数 的 一 个 参 数 , 无 则 NULL. 可 以 是 任 意 类 型<br />
线 程 的 终 止<br />
线 程 函 数 正 常 终 止 返 回 ;<br />
自 调 用 pthear_exit() 函 数 ;<br />
线 程 被 取 消 ;<br />
线 程 接 收 到 中 止 的 信 号 ;<br />
当 主 进 程 执 行 exit() 后 , 进 程 及 其 全 部 线 程 全 部 终 止 .<br />
2006 年 4 月 共 享 存 储 编 程 15/108
pthread_join(pthread_t wait_for,void** status);<br />
等 待 直 到 线 程 结 束 ;<br />
执 行 该 函 数 的 线 程 发 生 阻 塞 , 直 到 由 wait_for 指 定 的 线 程 终 止 ;<br />
等 与 被 等 的 两 线 程 必 须 是 同 一 进 程 内 部 的 线 程 ( 而 且 不 是 分 离 线<br />
程 );<br />
返 回 值<br />
⌧0<br />
⌧ESRCH<br />
程 ;<br />
成 功 返 回<br />
⌧EINVAL 线 程 参 数 无 效 ;<br />
⌧EDEADLK 等 待 自 身 结 束 .<br />
参 数 wait_for 指 定 的 线 程 不 存 在 或 是 一 分 离 线<br />
不 能 有 两 个 线 程 同 时 等 待 同 一 个 线 程 的 结 束 , 否 则 其 中 一 个 线 程<br />
正 常 返 回 , 另 外 一 个 返 回 ESRCH 错 误 .<br />
2006 年 4 月 共 享 存 储 编 程 16/108
Hello World(2)<br />
#include <br />
#include "stdio.h"<br />
Hello World from from thread 0! 0!<br />
#define numthrds 5<br />
Hello World from from thread 1! 1!<br />
pthread_t *tid;<br />
Hello World from from thread 2! 2!<br />
void *worker();<br />
Hello World from from thread 3! 3!<br />
main(){<br />
Hello World from from thread 4! 4!<br />
int i;<br />
tid = (pthread_t*) calloc(numthrds,sizeof(pthread_t));<br />
for(i=0;i
Hello World(3)<br />
#include <br />
#include "stdio.h"<br />
#define numthrds 5<br />
pthread_t *tid;<br />
pthread_mutex_t mutex;<br />
int sum=0;<br />
void *worker();<br />
main(){<br />
int i;<br />
}<br />
void *worker(){<br />
int myid,num;<br />
myid = pthread_self() - tid[0];<br />
printf("%d was added to the<br />
sum in thread %d\n",myid*10,myid);<br />
pthread_mutex_lock(&mutex);<br />
sum += myid*10;<br />
pthread_mutex_unlock(&mutex);<br />
return;<br />
}<br />
tid = (pthread_t*) calloc(numthrds,sizeof(pthread_t));<br />
pthread_mutex_init(&mutex,NULL);<br />
for(i=0;i
运 行 结 果<br />
0 was added to the sum in thread 0<br />
10 was added to the sum in thread 1<br />
20 was added to the sum in thread 2<br />
30 was added to the sum in thread 3<br />
40 was added to the sum in thread 4<br />
The sum is 100<br />
2006 年 4 月 共 享 存 储 编 程 19/108
基 于 多 线 程 编 程 的 PI 求 解<br />
2<br />
2<br />
∫<br />
1<br />
0<br />
1−<br />
x<br />
dx<br />
=<br />
2 π<br />
4<br />
2006 年 4 月 共 享 存 储 编 程 20/108
#include<br />
#include<br />
<br />
<br />
#include<br />
#include<br />
"stdio.h"<br />
"stdio.h"<br />
pthread_mutex_t<br />
pthread_mutex_t<br />
reduction_mutex;<br />
reduction_mutex;<br />
pthread_t<br />
pthread_t<br />
*tid;<br />
*tid;<br />
double<br />
double<br />
pi,w;<br />
pi,w;<br />
int<br />
int<br />
n;<br />
n;<br />
int<br />
int<br />
num_threads;<br />
num_threads;<br />
double<br />
double<br />
f(a)<br />
f(a)<br />
double<br />
double<br />
a;<br />
a;<br />
{<br />
{<br />
return<br />
return<br />
(4.0/(1.0<br />
(4.0/(1.0<br />
+<br />
+<br />
a*a));<br />
a*a));<br />
}<br />
}<br />
void<br />
void<br />
*PIworker(void*<br />
*PIworker(void*<br />
arg)<br />
arg)<br />
{<br />
{<br />
int<br />
int<br />
i,myid;<br />
i,myid;<br />
double<br />
double<br />
sum,mypi,x;<br />
sum,mypi,x;<br />
/*set<br />
/*set<br />
individual<br />
individual<br />
id<br />
id<br />
to<br />
to<br />
start<br />
start<br />
at<br />
at<br />
0 */<br />
*/<br />
myid<br />
myid<br />
=<br />
=<br />
pthread_self()<br />
pthread_self()<br />
-<br />
-<br />
tid[0];<br />
tid[0];<br />
/*integrate<br />
/*integrate<br />
function*/<br />
function*/<br />
sum=0.0;<br />
sum=0.0;<br />
for(i<br />
for(i<br />
= myid<br />
myid<br />
+ 1;i<br />
1;i<br />
gcc gcchello.c –lpthread<br />
a.out a.out 1000 10005<br />
computed pi pi = 3.1415927369231271<br />
转 去 Openmp<br />
void<br />
void<br />
main(argc,argv)<br />
main(argc,argv)<br />
int<br />
int<br />
argc;<br />
argc;<br />
char*<br />
char*<br />
argv[];<br />
argv[];<br />
{<br />
{<br />
int<br />
int<br />
i;<br />
i;<br />
/*check<br />
/*check<br />
command<br />
command<br />
line<br />
line<br />
*/<br />
*/<br />
if(argc<br />
if(argc<br />
!=<br />
!=<br />
3)<br />
3)<br />
{<br />
{<br />
printf("Usage:<br />
printf("Usage:<br />
%s<br />
%s<br />
Num_intervals<br />
Num_intervals<br />
Num_threads\n",argv[0]);<br />
Num_threads\n",argv[0]);<br />
exit(0);<br />
exit(0);<br />
}<br />
}<br />
/*get<br />
/*get<br />
num<br />
num<br />
intervals<br />
intervals<br />
and<br />
and<br />
num<br />
num<br />
threads<br />
threads<br />
from<br />
from<br />
command<br />
command<br />
line*/<br />
line*/<br />
n =<br />
=<br />
atoi(argv[1]);<br />
atoi(argv[1]);<br />
num_threads<br />
num_threads<br />
=<br />
=<br />
atoi(argv[2]);<br />
atoi(argv[2]);<br />
w =<br />
=<br />
1.0<br />
1.0<br />
/<br />
/<br />
(double)n;<br />
(double)n;<br />
pi<br />
pi<br />
=<br />
=<br />
0.0;<br />
0.0;<br />
tid<br />
tid<br />
=<br />
=<br />
(pthread_t*)<br />
(pthread_t*)<br />
calloc<br />
calloc<br />
(num_threads,sizeof(pthread_t));<br />
(num_threads,sizeof(pthread_t));<br />
/*initilize<br />
/*initilize<br />
lock*/<br />
lock*/<br />
if(pthread_mutex_init(&reduction_mute<br />
if(pthread_mutex_init(&reduction_mute<br />
x,NULL)){<br />
x,NULL)){<br />
fprintf(stderr,"Cannot<br />
fprintf(stderr,"Cannot<br />
init<br />
init<br />
lock\n");<br />
lock\n");<br />
exit(1);<br />
exit(1);<br />
}<br />
}<br />
/*create<br />
/*create<br />
the<br />
the<br />
threads*/<br />
threads*/<br />
for(i<br />
for(i<br />
= 0;<br />
0;<br />
i
多 线 程 并 行 编 程 特 点<br />
pthread_create() 创 建 一 个 新 线 程 比 重 新 启 动 一 个 线 程 花 费 的 时 间<br />
少 : 需 要 时 创 建 + 任 务 结 束 立 刻 杀 掉 vs. 维 护 一 大 堆 的 空 闲 线 程 并 且<br />
相 互 切 换 .<br />
在 加 锁 的 前 提 下 访 问 共 享 资 源<br />
不 支 持 数 据 并 行 , 适 合 于 任 务 级 并 行 , 即 一 个 线 程 单 独 执 行 一 个 任 务 ;<br />
不 支 持 增 量 并 行 化 , 对 于 一 个 串 行 程 序 , 很 难 用 Pthreads 进 行 并 行 化<br />
Pthreads 主 要 是 面 向 操 作 系 统 , 而 不 是 为 高 性 能 计 算 设 计 的 , 因 此<br />
不 是 并 行 计 算 程 序 设 计 的 主 流 平 台 。 但 是 “ 多 线 程 并 发 执 行 ” 这 种 思<br />
想 却 被 广 泛 地 应 用 于 高 性 能 计 算 。 这 就 是 我 们 即 将 要 讲 的 共 享 存 储<br />
并 行 编 程 的 另 外 一 种 被 并 行 机 制 造 商 和 广 用 并 行 计 算 用 户 广 泛 接 受<br />
的 平 台 :OpenMP<br />
2006 年 4 月 共 享 存 储 编 程 23/108
并 行 编 程 标 准<br />
线 程 库 标 准 (Thread Library)<br />
– Win32 API.<br />
– POSIX threads 线 程 模 型 .<br />
– X3H5: 概 念 性 线 程 模 型<br />
编 译 制 导 (Compiler Directives)<br />
– OpenMP - portable shared memory parallelism.<br />
2006 年 4 月 共 享 存 储 编 程 24/108
www.openmp.org<br />
•An Industry Standard API for Shared Memory Programming<br />
•An API for Writing Multithreaded Applications<br />
• 一 系 列 编 译 制 导 语 句 和 库 函 数<br />
• 使 得 Fortran, C and C++ 的 多 线 程 编 程 更 加 容 易<br />
2006 年 4 月 共 享 存 储 编 程 25/108
与 X3H5 的 关 系<br />
X3H5 是 ANSI/X3 授 权 的 小 组 委 员 会 , 主 要 目 的 是 在 PCF(the<br />
Parallel Computing Forum) 工 作 的 基 础 上 , 发 展 并 行 计 算 的 一 个<br />
ANSI 标 准 . PCF 是 一 非 正 式 的 工 业 组 织 , 虽 在 DO 循 环 的 并 行 化 方 法<br />
的 标 准 化 方 面 做 一 些 工 作 , 但 在 起 草 拟 了 一 个 标 准 后 就 草 草 收 场 .<br />
OpenMP 专 门 针 对 这 类 并 行 化 问 题 , 并 完 成 了 这 项 工 作 , 同 时 得 到 工<br />
业 界 的 广 泛 支 持 .<br />
2006 年 4 月 共 享 存 储 编 程 26/108
ANSI X3H5 共 享 编 程 标 准<br />
概 念 性 的 编 程 模 型 (ANSI 标 准 (1993))<br />
没 有 任 何 商 品 化 的 共 享 存 储 器 系 统 依 附 于 X3H5, 但 X3H5 的 基 本 概 念 影<br />
响 以 后 共 享 存 储 器 系 统 的 并 行 编 程 .( 一 些 基 本 概 念 在 OpenMP 均 出 现 !)<br />
X3H5 支 持 C,Fortran77 以 及 Fortran90 语 言 .<br />
X3H5 规 定 的 基 本 的 并 行 结 构 用 于 并 行 性 表 述 :<br />
并 行 块 ( 分 散 任 务 Work Sharing)<br />
并 行 循 环<br />
单 进 程<br />
psections<br />
psections<br />
{<br />
{<br />
…<br />
}<br />
}<br />
end<br />
end<br />
psections<br />
psections<br />
parallel<br />
parallel<br />
{<br />
{<br />
…<br />
}<br />
}<br />
end<br />
end<br />
parallel<br />
parallel<br />
pdo<br />
pdo<br />
{<br />
{<br />
…<br />
}<br />
}<br />
end<br />
end<br />
pdo<br />
pdo<br />
psingle<br />
psingle<br />
{<br />
{<br />
…<br />
}<br />
}<br />
end<br />
end<br />
psingle<br />
psingle<br />
2006 年 4 月 共 享 存 储 编 程 27/108
X3H5 编 程 实 例<br />
program main<br />
! 程 序 以 顺 序 模 式 执 行<br />
A<br />
!A 只 由 基 本 线 程 执 行<br />
线 程 P Q R<br />
parallel<br />
! 转 换 成 并 行 模 式<br />
B<br />
!B 为 每 个 组 员 所 复 制<br />
psections ! 并 行 块 开 始<br />
隐 式 barrier<br />
section<br />
B B B<br />
C<br />
! 一 个 组 员 执 行 C<br />
section<br />
C D<br />
D<br />
! 另 一 个 组 员 执 行 D<br />
隐 式 barrier<br />
end psections ! 等 待 C 和 D 都 结 束<br />
E<br />
psingle<br />
暂 时 转 换 成 顺 序 模 式<br />
E<br />
!E 只 能 被 一 个 组 员 执 行 隐 式 barrier<br />
end psingle ! 转 回 并 行 模 式<br />
F(1:2) F(3:4) F(5:6)<br />
pdo I=1,6 ! 并 行 do 循 环 开 始<br />
无 隐 式 barrier<br />
F(i)<br />
! 各 线 程 分 担 循 环 任 务<br />
G G G<br />
end pdo no wait ! 无 隐 式 路 障 同 步<br />
隐 式 barrier<br />
G<br />
! 更 多 的 复 制 代 码<br />
end parallel<br />
! 结 束 并 行 模 式<br />
H<br />
H<br />
! 根 进 程 执 行 H<br />
…<br />
! 更 多 的 并 行 构 造<br />
各 线 程 以 负 载 平 衡 方 式 分 担 任 务<br />
2006 end年 4 月 共 享 存 储 编 程 28/108<br />
各 线 程 以 负 载 平 衡 方 式 分 担 任 务<br />
可 能 为 :F(1:1),F(2:2),F(3:6)…
X3H5 例 程 执 行 过 程 描 述<br />
程 序 以 顺 序 方 式 启 动 , 此 时 只 有 一 个 初 始 化<br />
线 程 , 称 为 基 本 线 程 或 主 线 程 . 当 程 序 遇 到<br />
parallel 时 , 通 过 派 生 多 个 子 线 程 转 换 为 并<br />
行 执 行 模 式 ( 线 程 数 隐 式 决 定 ). 基 本 线 程 与<br />
它 的 子 线 程 形 成 一 个 组 . 所 有 组 员 并 行 处 理<br />
后 继 并 行 代 码 , 直 至 end parallel. 然 后 程<br />
序 转 为 顺 序 模 式 , 只 有 基 本 线 程 继 续 执 行 .<br />
子 线 程 遇 到 内 部 并 行 或 任 务 分 担 构 造 时 , 可<br />
以 继 续 派 生 其 子 线 程 , 从 而 成 为 一 个 新 组 的<br />
基 本 线 程 .<br />
线 程 间 同 步 , 通 信 与 交 互<br />
隐 式 路 障 :parallel, end parallel,<br />
end pdo 或 end psingle 处 隐 式<br />
barrier. 如 果 不 需 , 则 加 no wait;<br />
各 处 理 机 通 过 全 局 变 量 通 信 , 通 过 私 有<br />
变 量 封 装 数 据<br />
顺 序 执 行<br />
fork<br />
…...<br />
barrier<br />
顺 序 执 行<br />
…<br />
并 行 执 行<br />
2006 年 4 月 共 享 存 储 编 程 29/108
OpenMP: 并 行 模 型<br />
Fork-Join 并 行 模 式 :<br />
主 线 程 根 据 需 要 创 建 一 组 子 线 程 进 行 工 作 分 担 .<br />
可 对 串 行 程 序 进 行 逐 步 并 行 化 .<br />
主 线 程<br />
并 行 执 行 区 域<br />
2006 年 4 月 共 享 存 储 编 程 30/108
如 何 应 用 OpenMP?<br />
OpenMP 常 用 于 循 环 并 行 化 :<br />
– 找 出 最 耗 时 的 循 环 .<br />
– 将 循 环 由 多 线 程 完 成 .<br />
在 串 行 程 序 上 加 上 编 译 制 导 语 句 , 完 成 并 行 化 , 因 此 可 先 完 成 串 行<br />
程 序 , 然 后 再 进 行 OpenMP 并 行 化 .<br />
用 OpenMP 将 该 循 环 通 过 多 线 程 进 行 任 务 分 割<br />
void void main() main()<br />
{{<br />
double double Res[1000]; Res[1000];<br />
for(int for(inti=0;i
线 程 间 如 何 交 互 ?<br />
OpenMP 是 基 于 共 享 内 存 模 型 .<br />
线 程 通 过 共 享 变 量 通 信 .<br />
访 问 共 享 变 量 会 导 致 race condition ( 竞 态 状 态 )<br />
race condition: 是 一 种 状 态 , 在 这 种 状 态 下 两 个 实 体 ( 例 如 两 个 处<br />
理 过 程 ) 对 同 一 资 源 进 行 竞 争 , 而 系 统 没 有 一 种 机 制 来 测 定 首 先 要<br />
执 行 的 是 哪 一 个 。 因 此 , 由 于 系 统 不 能 保 证 数 据 的 正 确 处 理 , 其<br />
结 果 是 不 可 预 测 的 。<br />
为 了 避 免 线 程 进 入 竞 态 状 态 :<br />
通 过 同 步 对 象 来 保 护 数 据 冲 突 .<br />
2006 年 4 月 共 享 存 储 编 程 32/108
OpenMP 术 语<br />
大 多 OpenMP 构 造 是 制 导 语 句 或 pragmas.<br />
C 和 C++ 的 pragmas 形 式 为 :<br />
⌧#pragma omp construct [<strong>clause</strong> [<strong>clause</strong>]…]<br />
Fortran 中 , 制 导 语 句 形 式 为 以 下 几 种 :<br />
⌧C$OMP CONSTRUCT [<strong>clause</strong> [<strong>clause</strong>]…]<br />
⌧!$OMP CONSTRUCT [<strong>clause</strong> [<strong>clause</strong>]…]( 自 由 书 写 格 式 唯 一 )<br />
⌧*$OMP CONSTRUCT [<strong>clause</strong> [<strong>clause</strong>]…]<br />
⌧ 例 : 以 下 三 种 等 价 ( 第 一 行 为 列 数 )<br />
⌧C23456789<br />
⌧!$OMP PARALLEL DO SHARED(A,B,C)<br />
⌧C$OMP PARALLEL DO<br />
⌧C$OMP+SHARED(A,B,C)<br />
⌧C$OMP PARALLELDOSHARED(A,B,C)<br />
由 于 OpenMP 构 造 为 注 释 性 语 句 , 因 此 一 个 OpenMP 程 序 在 用 不 支 持<br />
OpenMP 的 编 译 器 编 译 后 , 仍 为 串 行 程 序 .<br />
2006 年 4 月 共 享 存 储 编 程 33/108
Structured blocks( 结 构 化 块 )<br />
结 构 化 块 性 质 :<br />
仅 在 块 顶 有 一 个 入 口 和 块 底 有 一 个 出 口 ;<br />
块 功 能 可 通 过 构 造 的 语 法 清 晰 地 识 别 ;<br />
块 内 除 Fortran 中 的 STOP 语 句 和 c/c++ 中 的 exit() 语 句 外 , 不 能 有 其<br />
它 分 支 .<br />
大 多 OpenMP 构 造 为 结 构 化 块 .<br />
C$OMP PARALLEL<br />
10 …<br />
…<br />
if(…) goto 10<br />
C$OMP END PARALLEL<br />
print *,id<br />
C$OMP PARALLEL<br />
10 …<br />
30 …<br />
if(…) goto 20<br />
go to 10<br />
C$OMP END PARALLEL<br />
if(…) goto 30<br />
20 print *, id<br />
一 个 结 构 化 块<br />
一 个 非 结 构 化 块<br />
2006 年 4 月 共 享 存 储 编 程 34/108
OpenMP 结 构 化 块 类 型<br />
OpenMP 主 要 有 五 类 结 构 化 块 :<br />
并 行 区 Parallel Regions<br />
任 务 分 割 Worksharing<br />
数 据 环 境 Data Environment<br />
同 步 Synchronization<br />
运 行 时 函 数 / 环 境 变 量<br />
在 Fortran,C/C++ 中 ,OpenMP 基 本 上 是 一 样 的 .<br />
2006 年 4 月 共 享 存 储 编 程 35/108
Parallel Regions( 并 行 区 )<br />
并 行 区 是 OpenMP 的 基 本 构 造 , 并 行 区 内 的 代 码 由 各 线 程 同 时 执 行 .<br />
当 一 个 线 程 执 行 “omp parallel” 后 , 建 立 一 组 线 程 , 该 线 程 成 为 新 建 立 的<br />
线 程 组 的 主 线 程 . 所 有 线 程 构 成 一 线 程 组 , 各 线 程 以 线 程 ID 区 分 , 主 线 程<br />
ID 为 0.<br />
线 程 组 并 行 执 行 并 行 区 内 代 码 .<br />
如 : 建 立 一 个 4 线 程 的 并 行 区 :<br />
每 一 线 程 以 不 同 的 线 程 ID ID<br />
和 相 同 的 参 数 A 执 行 并 行<br />
区 内 代 码 的 一 拷 贝 ..<br />
ID(=0,1,2,3).<br />
double A[1000];<br />
omp_set_num_threads(4);<br />
#pragma omp ompparallel<br />
{{<br />
int intID ID = omp_thread_num();<br />
worker(ID,A);<br />
}}<br />
2006 年 4 月 共 享 存 储 编 程 36/108
并 行 区 的 Lecical / dynamic extent<br />
以 及 Orphaned 制 所 语 句<br />
poo.f<br />
C$OMP PARALLEL<br />
call whoami<br />
C$OMP END END PARALLEL<br />
Static/lexical<br />
extent: 在 书 写 上 直 接<br />
包 含 在 并 行 区 内 的 部 分 .<br />
Dynamic extent: 包 括<br />
并 行 区 内 直 接 和 间 接 ( 函 数<br />
调 用 ) 包 含 的 内 容 , 也 被 称<br />
为 region.<br />
+<br />
bar.f<br />
subroutine whoami<br />
external omp_get_thread_num<br />
integer iam, iam, omp_get_thread_num<br />
iam iam = omp_get_thread_num()<br />
C$OMP C$OMP CRITICAL<br />
print*,’Hello from from ‘, ‘, iam iam<br />
C$OMP C$OMP END END CRITICAL<br />
return<br />
end end<br />
Orphan 制 导 语 句 : 落 在 子 程 序<br />
中 的 制 导 语 句 , 方 便 于 子 程 序 的<br />
并 行 化 , 免 去 传 统 的 inline 处 理<br />
2006 年 4 月 共 享 存 储 编 程 37/108
并 行 区 代 码 流 程<br />
每 一 线 程 执 行 相 同 代 码 , 不 , 同 数 据 ..<br />
Double A[1000]<br />
opm_set_num_threads(4)<br />
double A[1000];<br />
omp_set_num_threads(4);<br />
#pragma omp ompparallel<br />
{{<br />
int intID ID = omp_thread_num();<br />
worker(ID,A);<br />
}}<br />
worker(0,A)<br />
worker(1,A)<br />
worker(2,A)<br />
worker(3,A)<br />
所 有 线 程 在 此 处 同 步 ( 如 , 隐 式 barrier 同 步 )<br />
所 以 , 并 行 区 结 构 也 被 称 为 SPMD 结 构 .<br />
2006 年 4 月 共 享 存 储 编 程 38/108
Hello World(C)<br />
#include <br />
main()<br />
{<br />
int myid,numthreads;<br />
#pragma omp parallel<br />
{<br />
myid = omp_get_thread_num();<br />
numthreads = omp_get_num_threads();<br />
printf("Hello World from thread %d of<br />
%d!\n",myid,numthreads);<br />
}<br />
}<br />
2006 年 4 月 共 享 存 储 编 程 39/108
Hello World(Fortran)<br />
PROGRAM HELLO<br />
integer myid,numthreads<br />
integer omp_get_num_threads,omp_get_thread_num<br />
!$omp parallel private(numthreads,myid)<br />
numthreads = omp_get_num_threads()<br />
myid = omp_get_thread_num()<br />
print *, 'Hello World from thread' ,myid,'of',numthreads<br />
!$omp end parallel<br />
stop<br />
end<br />
2006 年 4 月 共 享 存 储 编 程 40/108
OpenMP 并 行 程 序 编 译<br />
• 支 持 编 译 OpenMP 的 编 译 器 会 提 供 编 译 器 命 令 选 项 , 以 解 释 OpenMP 编 译 制<br />
导 语 句 .<br />
• IBM AIX xlc 编 译 器 , 编 译 器 命 令 选 项 为 -qsmp<br />
• xlc file.c –qsmp<br />
• xlf_r file.f -qsmp (xlf_r 为 IBM AIX4.3 为 支 持 多 线 程 编 程 的 编 译 器 )<br />
• 曙 光 3000:OS: AIX4.3 -qsmp AIX4.3 支 持 OpenMP 编 译 选 项<br />
• Intel C/C++ 编 译 器 icc, Intel Fortran 编 译 器 选 项 为 -openmp<br />
• icc file.c –openmp<br />
• ifc file.f –openmp<br />
• 曙 光 4000L:OS:Redhat Linux 8.0<br />
• PGI C/C++ 编 译 器 icc, PGI Fortran 编 译 器 选 项 为 -mp<br />
• pgcc file.c –mp<br />
• pgf77 file.f –mp<br />
• pgf90 file.f –mp<br />
• 曙 光 4000A:OS:SuSE Linux 8.0 / Turbo Linux<br />
2006 年 4 月 共 享 存 储 编 程 41/108
一 些 细 节 ( 可 先 不 关 心 )<br />
C:<br />
#pragma omp parallel [<strong>clause</strong>[ <strong>clause</strong>] ...] new-line<br />
structured-block<br />
Fortran:<br />
!$OMP PARALLEL [<strong>clause</strong>[[,] <strong>clause</strong>]...]<br />
block<br />
!$OMP END PARALLEL<br />
子 句 <strong>clause</strong> 是 下 列 之 一 :<br />
if(expr): 根 据 expr 表 达 式 执 行 结 果 决 定 是 否 并 行 执 行<br />
private(list): 变 量 私 有 化 , 默 认 为 全 部 变 量<br />
firstprivate(list): 在 并 行 区 间 之 外 引 用 变 量 首 次 赋 值 结 果<br />
default(shared | none)(C)<br />
DEFAULT(PRIVATE | SHARED | NONE)(Fortran)<br />
shared(list): 并 行 区 间 中 的 共 享 变 量 列 表<br />
copyin(list): 拷 贝 主 线 程 的 threadprivate 公 共 区 数 据<br />
reduction(operator: list): 归 约 操 作<br />
2006 年 4 月 共 享 存 储 编 程 42/108
OpenMP 结 构 化 块 类 型<br />
OpenMP 主 要 有 五 类 结 构 化 块 :<br />
并 行 区 Parallel Regions<br />
OpenMP 最 重 要 部 分<br />
任 务 分 割 Worksharing<br />
⌧DO(Fortran)/for(C) 结 构 : 针 对 循 环 的 并 行 化 结 构<br />
⌧Sections: 代 码 段 间 的 并 行<br />
⌧Single: 强 制 并 行 区 中 某 些 代 码 以 串 行 方 式 执 行 ( 如 :I/O)<br />
数 据 环 境 Data Environment<br />
同 步 Synchronization<br />
运 行 时 函 数 / 环 境 变 量<br />
2006 年 4 月 共 享 存 储 编 程 43/108
循 环 分 割 :DO(Fortran)/for(C)<br />
结 构<br />
Fortran<br />
!$OMP DO [<strong>clause</strong>[[,] <strong>clause</strong>]...]<br />
do_loop<br />
[!$OMP END DO [NOWAIT]]( 可 选 )<br />
C/C++<br />
#pragma omp for [<strong>clause</strong>[ <strong>clause</strong>] ... ]<br />
new-line<br />
for-loop<br />
C$OMP PARALLEL<br />
C$OMP DO<br />
DO i=0,n<br />
…<br />
}<br />
#pragma omp parallel<br />
#pragma omp for<br />
for (i=0;i
比 较 parrallel 构 造 与 for 构 造<br />
串 行 代 码<br />
用 并 行 区 实 现 并 行 化<br />
用 任 务 分 割 构 造 实 现 并 行 化<br />
for(i=0;I
并 行 区 与 任 务 分 割 间 的 关 系<br />
并 行 区 和 任 务 分 割 是 OpenMP 两 类 基<br />
本 的 并 行 性 构 造 ;<br />
根 进 程<br />
并 行 区 中 的 代 码 对 组 内 的 各 线 程 是 可 见<br />
的 , 也 即 并 行 区 内 的 代 码 由 各 线 程 同 时<br />
执 行 ;<br />
任 务 分 割 与 并 行 区 不 同 , 它 是 将 一 个 整<br />
体 任 务 按 负 载 平 衡 的 方 式 分 配 给 各 线 程<br />
来 互 相 配 合 完 成 .<br />
并 行 区 是 并 行 的 先 决 条 件 , 任 务 分 割 必<br />
须 要 与 并 行 区 一 起 使 用 才 能 生 效 ;<br />
并 行 区 构 造 为 !omp parallel;<br />
任 务 分 割 构 造 有 :do/for,section, 和<br />
single 三 种 .<br />
并 行 区<br />
2006 年 4 月 共 享 存 储 编 程 46/108
更 详 细 的 for 语 法<br />
#pragma omp for [<strong>clause</strong>[ <strong>clause</strong>] ... ] new-line<br />
for-loop<br />
Clause 可 是 下 列 说 明 :<br />
private(list)<br />
firstprivate(list)<br />
lastprivate(list)<br />
reduction(operator: list)<br />
ordered<br />
schedule(kind[, chunk_size])<br />
nowait<br />
后 面 将 详 细<br />
说 明<br />
2006 年 4 月 共 享 存 储 编 程 47/108
更 详 细 的 DO 语 法<br />
!$OMP DO [<strong>clause</strong>[[,] <strong>clause</strong>]...]<br />
do_loop<br />
[!$OMP END DO [NOWAIT]]<br />
PRIVATE(list)<br />
FIRSTPRIVATE(list)<br />
LASTPRIVATE(list)<br />
REDUCTION({operator|intrinsic_procedure_name}:list)<br />
SCHEDULE(type[,chunk])<br />
ORDERED<br />
2006 年 4 月 共 享 存 储 编 程 48/108
DO/for 使 用 注 意 事 项<br />
循 环 体 必 须 紧 接 在 DO 或 for 之 后 .<br />
For 循 环 必 须 为 一 结 构 化 块 , 且 其 执 行 不 被 break 语 句 中<br />
断 .<br />
在 Fortran 中 , 如 果 写 上 END DO 制 导 语 句 , 其 必 须 要 紧 跟 在<br />
DO 循 环 的 结 束 之 后 .<br />
循 环 变 量 必 须 为 整 形 .<br />
Schedule, ordered,nowait 子 句 只 能 出 现 一 次 .<br />
2006 年 4 月 共 享 存 储 编 程 49/108
schedule<br />
Schedule 子 名 决 定 循 环 如 何 在 各 线 程 中 进 行 分 配 :<br />
schedule(dynamic[,chunk])<br />
各 线 程 每 次 得 到 chunk_size 大 小 的 任 务 , 执 行 完 后 继 续 取 得 任 务 , 以 此 反<br />
复 , 直 至 任 务 完 成 ( 最 后 一 任 务 可 能 会 小 于 chunk_size).( 任 务 池 )<br />
当 chunk_size 未 被 指 定 时 , 默 认 为 1.<br />
schedule(static[,chunk])<br />
如 果 chunk_size 被 指 定 , 则 各 线 程 按 线 程 号 顺 序 每 人 每 得 chunk 次 的<br />
循 环 任 务 , 如 果 任 务 不 能 一 次 平 分 掉 , 则 分 配 循 环 进 行 .<br />
如 果 chunk_size 未 被 指 定 , 则 各 线 程 任 务 数 即 为 循 环 数 除 以 所 用 线 程 数<br />
的 结 果 .<br />
schedule(guided[,chunk])<br />
开 始 以 一 大 的 单 位 进 行 分 配 忆 , 逐 渐 减 小 到 chunk 指 定 的 值 .<br />
schedule(runtime)<br />
分 配 方 式 与 chunk 值 大 小 取 决 于 环 境 变 量 OMP_SCHEDULE 的 设 置 .<br />
chunk 以 循 环 次 数 为 单 位 .<br />
示 意 图 见 下 页 .<br />
2006 年 4 月 共 享 存 储 编 程 50/108
Schedule 示 意 图<br />
Work pool<br />
Work<br />
Work<br />
.. .. .. ..<br />
..<br />
执<br />
行<br />
时 .<br />
间<br />
.<br />
.<br />
.<br />
.<br />
.<br />
Dynamic 方 式<br />
Static 方 式<br />
Guided 方 式<br />
2006 年 4 月 共 享 存 储 编 程 51/108
适 用 条 件<br />
静 态 : 适 用 于 大 部 分 情 形 .<br />
特 点 :<br />
⌧ 各 线 程 任 务 明 确 , 在 任 务 分 配 时 无 需 同 步 操 作 .<br />
⌧ 运 行 快 的 线 程 需 等 慢 的 线 程 为 :<br />
动 态 : 适 用 于 任 务 数 量 可 变 或 不 确 定 的 情 形 ( 如 条 件 收 敛 循 环 ).<br />
特 点 :<br />
⌧ 各 线 程 将 要 执 行 的 任 务 不 可 预 见 , 任 务 分 配 需 同 步 操 作 .<br />
Guided: 线 程 异 步 到 达 for 结 构<br />
特 点 :<br />
⌧ 首 先 到 达 的 线 程 总 是 分 得 q=ceiling(n/p) 次 循 环 , 然 后<br />
n=max(n-q,p*k), 循 环 分 配 , 直 到 n=p*k 为 止 .<br />
环 境 变 量 : 无 需 重 新 编 译 程 序 , 可 根 据 原 始 输 入 数 据 的 情 况 改 变 任 务 分<br />
配 策 略 .<br />
2006 年 4 月 共 享 存 储 编 程 52/108
NOWAIT 子 句 (Fortran)<br />
C$OMP PARALLEL<br />
C$OMP DO<br />
do i=1,n<br />
a(i)= cos(a(i))<br />
enddo<br />
C$OMP END DO<br />
隐 式<br />
C$OMP DO<br />
BARRIER<br />
do i=1,n<br />
b(i)=a(i)+b(i)<br />
enddo<br />
C$OMP END DO<br />
C$OMP END PARALLEL<br />
默 认 循 环 变 量 i 为 私 有 线 程 私 有 类 型 变 量<br />
C$OMP PARALLEL<br />
C$OMP DO<br />
do i=1,n<br />
a(i)= cos(a(i))<br />
enddo<br />
C$OMP END DO NOWAIT<br />
C$OMP DO<br />
No<br />
do i=1,n BARRIER<br />
b(i)=a(i)+b(i)<br />
enddo<br />
C$OMP END DO<br />
C$OMP END PARALLEL<br />
END DO 必 须 紧 随 enddo, 可 省 略 .<br />
2006 年 4 月 共 享 存 储 编 程 53/108
no wait 子 句 (C)<br />
#pragma omp parallel<br />
{<br />
#pragma omp for<br />
for(i=1;i
Sections 构 造 ( 非 循 环 并 行 )<br />
Sections 用 于 程 序 中 大 范 围 的 非 迭 代 执 行 代 码 段 间 的 并 行 化 .( 如 前 10<br />
行 和 后 10 行 间 代 码 间 无 依 赖 关 系 , 可 以 并 行 .)<br />
#pragma omp sections [no wait]<br />
{<br />
x_calculation();<br />
#pragma omp section<br />
y_calculation();<br />
#pragma omp section<br />
z_calculation();<br />
}<br />
缺 省 时 每 一 个 “omp sections” 构 造 结 束 后 有 一 个 barrier 同 步 操 作 . 通 过<br />
使 用 “nowait” 子 句 禁 止 隐 式 barrier 同 步 ( 在 构 造 语 句 后 直 接 加 即 可 ).<br />
与 for 结 构 相 类 似 ,OpenMP 也 提 供 parallel sections.<br />
x_calculation(),y_calc<br />
ulation() 以 及<br />
z_calculation() 代 表 三<br />
部 分 之 间 无 依 赖 关 系<br />
的 非 循 环 代 码 段 . 实<br />
质 上 它 们 各 代 表 很 多<br />
行 代 码 .<br />
2006 年 4 月 共 享 存 储 编 程 55/108
Single<br />
Single: 强 制 并 行 区 中 某 些 代 码 以 串 行 方 式 执 行<br />
#pragma omp single [<strong>clause</strong>[ <strong>clause</strong>] ...] new-line<br />
⌧structured-block<br />
Clause is one of the following:<br />
⌧private(list)<br />
⌧firstprivate(list)<br />
⌧nowait<br />
2006 年 4 月 共 享 存 储 编 程 56/108
Work sharing 语 句 汇 总<br />
<br />
<br />
Fortran<br />
DO<br />
SECTIONS<br />
SINGLE<br />
WORKSHARE<br />
C<br />
for<br />
sections<br />
single<br />
2006 年 4 月 共 享 存 储 编 程 57/108
Binding<br />
并 行 结 构 的 联 合 使 用<br />
•for, sections, single, master, and barrier 如 果 不 位 于 并 行 区 内 或<br />
不 与 并 行 区 联 合 使 用 , 便 不 起 任 何 作 用 .<br />
#pragma omp parallel for<br />
for (I=0;I
Fortran<br />
!$OMP !$OMP PARALLEL DO DO [<strong>clause</strong>[[,] <strong>clause</strong>]...]<br />
do_loop do_loop<br />
[!$OMP [!$OMP END END PARALLEL DO] DO]<br />
!$OMP !$OMP PARALLEL PARALLEL SECTIONS SECTIONS [<strong>clause</strong>[[,] [<strong>clause</strong>[[,] <strong>clause</strong>]...] <strong>clause</strong>]...]<br />
[!$OMP [!$OMP SECTION SECTION ]]<br />
block block<br />
[!$OMP [!$OMP SECTION SECTION<br />
block] block]<br />
. . ..<br />
!$OMP !$OMP END END PARALLEL PARALLEL SECTIONS SECTIONS<br />
!$OMP !$OMP PARALLEL WORKSHARE [<strong>clause</strong>[[,]<br />
<strong>clause</strong>]...]<br />
block block<br />
!$OMP !$OMP END END PARALLEL WORKSHARE<br />
2006 年 4 月 共 享 存 储 编 程 59/108
C<br />
#pragma omp omp parallel for for [<strong>clause</strong>[ <strong>clause</strong>] ...] new-line<br />
for-loop<br />
#pragma omp omp parallel sections [<strong>clause</strong>[ <strong>clause</strong>] ...] new-line<br />
{<br />
[#pragma omp omp section new-line]<br />
structured-block<br />
[#pragma omp omp section new-line<br />
structured-block<br />
.<br />
.] .]<br />
}<br />
2006 年 4 月 共 享 存 储 编 程 60/108
OpenMP 结 构 化 块 类 型<br />
OpenMP 主 要 有 五 类 结 构 化 块 :<br />
并 行 区 Parallel Regions<br />
任 务 分 割 Worksharing<br />
数 据 环 境 Data Environment<br />
同 步 Synchronization<br />
运 行 时 函 数 / 环 境 变 量<br />
2006 年 4 月 共 享 存 储 编 程 61/108
默 认 数 据 类 型<br />
共 享 变 量 编 程 模 型 :<br />
– 大 部 分 变 量 默 认 为 共 享 类 型<br />
各 线 程 共 享 全 局 变 量<br />
– Fortran: COMMON 块 , SAVE 变 量 , MODULE 变 量<br />
– C: File scope variables, static<br />
但 并 不 是 所 有 变 量 全 部 共 享 ...<br />
– 在 并 行 区 内 调 用 的 子 程 序 中 的 栈 变 量 是 私 有<br />
– 在 语 句 块 中 的 Auto 变 量 为 私 有 变 量 .<br />
2006 年 4 月 共 享 存 储 编 程 62/108
举 例 说 明 变 量 类 型<br />
program sort<br />
common /input/ A(10)<br />
integer index(10)<br />
call input<br />
C$OMP PARALLEL<br />
call work(index)<br />
C$OMP END PARALLEL<br />
print*, index(1)<br />
subroutine work<br />
common /input/ A(10)<br />
real temp(10)<br />
integer count<br />
save count<br />
…………<br />
变 量 A,index 和 cound 为 所 有 线<br />
程 共 享 .<br />
temp 为 线 程 私 有 变 量 , 各 线 程 间<br />
到 不 可 见 .<br />
2006 年 4 月 共 享 存 储 编 程 63/108
变 量 类 型 改 变<br />
变 量 类 型 编 译 制 导 : threadprivate: 将 某 些 全 局 变 量 或 数 据 区 变 为<br />
线 程 私 有 .<br />
通 过 下 列 类 型 属 性 子 句 来 改 变 变 量 类 型 :<br />
– shared( 并 行 区 结 构 )<br />
– private<br />
– firstprivate<br />
– lastprivate: 循 环 体 内 的 私 有 变 量 可 以 转 变 为 全 局 变 量 , 在 循<br />
环 结 束 后 访 问 ;<br />
默 认 数 据 类 型 状 态 可 以 改 变 :<br />
– default (private | shared | none)<br />
2006 年 4 月 共 享 存 储 编 程 64/108
私 有 类 型 变 量<br />
变 量 私 有 化 是 OpenMP 采 用 的 重 要 的 编 译 技 术 .<br />
变 量 私 有 化 ;<br />
私 有 变 量 初 始 化 :<br />
⌧Copyin<br />
⌧Firstprivate<br />
私 有 变 量 返 回 :<br />
⌧Reduction<br />
⌧Lastprivate<br />
OpenMP 私 有 类 型 变 量 是 指 并 行 区 内 的 只 能 被 线 程 组 内 的 某 一 线 程 访 问 的<br />
变 量 .<br />
OpenMP 的 私 有 变 量 包 括 :<br />
并 行 区 内 定 义 的 变 量 ;<br />
由 threadprivate 制 导 语 句 指 明 的 变 量 ;<br />
由 private, firstprivate,lastprivate, or reduction 子 句 指 定 的 变<br />
量 ;<br />
循 环 控 制 变 量 .<br />
2006 年 4 月 共 享 存 储 编 程 65/108
Threadprivate:<br />
线 程 的 全 局 私 有 变 量<br />
parameter (N=1000)<br />
real A(N,N)<br />
C$OMP THREADPRIVATE(/buf/)<br />
common/buf/lft(N),rht(N)<br />
C$OMP PARALLEL<br />
call init<br />
call scale<br />
call order<br />
buf 是 线 程 内 的 公 共 块<br />
C$OMP END PARALLEL<br />
subroutine scale<br />
parameter (N=1000)<br />
C$OMP THREADPRIVATE(/buf/)<br />
common/buf/lft(N),rht(N)<br />
do i=1, N<br />
lft(i)= const* A(i,iam)<br />
end do<br />
return<br />
end<br />
subroutine order<br />
parameter (N=1000)<br />
C$OMP THREADPRIVATE(/buf/)<br />
common/buf/lft(N),rht(N)<br />
do i=1, N<br />
A(i,iam) = lft(index)<br />
end do<br />
return<br />
end<br />
2006 年 4 月 共 享 存 储 编 程 66/108
Private<br />
private(list) 表 明 list 中 所 列 变 量 为 组 内 线 程 私 有 变 量 .<br />
– 对 变 量 不 进 行 初 始 化 ( 有 构 造 函 数 除 外 )<br />
– 私 有 拷 贝 独 立 存 储 , 不 与 原 变 量 一 致<br />
main()<br />
{{<br />
int inti i = 10000;<br />
#pragma omp ompparallel private(i)<br />
{{<br />
i i = -10000;<br />
}}<br />
printf("%d\n",i);<br />
}}<br />
运 行 ::<br />
10000 10000<br />
main()<br />
{{<br />
int inti i = 10000;<br />
#pragma omp ompparallel<br />
{{<br />
i i = -10000;<br />
}}<br />
printf("%d\n",i);<br />
}}<br />
运 行 ::<br />
-10000<br />
2006 年 4 月 共 享 存 储 编 程 67/108
Private 变 量 将 在 组 内 每 一 线 程 中 进 行 创 建 , 如 果 只 有 如 果<br />
变 量 有 构 造 函 数 , 则 调 用 构 造 函 数 进 行 初 始 化 , 否 则 该 私 有<br />
变 量 的 值 不 确 定 .<br />
在 进 入 并 行 结 构 中 , 私 有 变 量 引 用 的 原 变 量 值 是 不 确 定 的 ;<br />
也 不 能 在 并 行 构 造 对 引 用 的 变 量 进 行 修 改 , 在 结 构 中 对 这<br />
些 对 私 有 变 量 的 修 改 不 影 响 退 出 结 构 后 的 同 名 变 量 值 .<br />
私 有 变 量 应 在 并 行 性 构 造 中 进 行 初 始 化 ;<br />
私 有 变 量 不 能 为 引 用 类 型 ( 破 坏 了 数 据 的 独 立 性 );<br />
2006 年 4 月 共 享 存 储 编 程 68/108
?<br />
For 结 构 中 :<br />
main(){<br />
int inti,sum=0,myid;<br />
#pragma omp ompparallel for for \\<br />
private(i,sum)<br />
for(i=0;i
Firstprivate<br />
Firstprivate 是 private 的 特 殊 情 况 .<br />
– 在 主 线 程 中 初 始 化 每 一 个 线 程 的 私 有 拷 贝 变 量 .<br />
main(){<br />
int i,sum=0,myid;<br />
#pragma omp parallel for firstprivate(i,sum)<br />
for(i=0;i
Lastprivate<br />
Lastprivate 将 位 于 迭 代 末 的 私 有 变 量 转 化 为 全 局 变 量 .<br />
for (i=1;i
Default<br />
默 认 情 形 =default(shared)( 因 此 不 显 示 使 用 )<br />
改 变 默 认 default(private):<br />
将 并 行 区 内 变 量 的 默 认 类 型 改 为 私 有 , 而 不 是 共 享<br />
省 去 在 每 一 并 行 区 结 构 后 加 private(list)<br />
default(none): 指 事 先 指 定 并 行 区 中 变 量 的 默 认 类 型<br />
Fortran 支 持 default(private).<br />
C/C++ 无 default(private), 只 有 default(shared) 和 default(none).<br />
2006 年 4 月 共 享 存 储 编 程 72/108
DEFAULT 例 (Fortran)<br />
itotal = 1000<br />
C$OMP PARALLEL PRIVATE(np, each)<br />
np = omp_get_num_threads()<br />
each = itotal/np<br />
………<br />
C$OMP END PARALLEL<br />
itotal = 1000<br />
C$OMP PARALLEL DEFAULT(PRIVATE) SHARED(itotal)<br />
np = omp_get_num_threads()<br />
each = itotal/np<br />
………<br />
C$OMP END PARALLEL<br />
2006 年 4 月 共 享 存 储 编 程 73/108
eduction<br />
归 约 操 作 ( 将 各 线 程 中 处 理 结 果 经 某 种 运 算 后 送 回 到 根 进 程 )<br />
reduction (op : list).<br />
List 中 所 列 变 量 必 须 为 并 行 区 内 的 共 享 变 量 .<br />
支 持 的 运 算 操 作 :<br />
Operator Initialization<br />
+ 0 #pragma omp parallel for private(i) shared(x, y, n)<br />
* 1 reduction(+: a, b)<br />
&& 1 for (i=0; i
实 例 :PIPI 求 解<br />
通 过 数 值 积 分 的 方 法 串 行 求 解 PI 很 简 单 的 ( 具 体 代 码 见 下 一 页 ).<br />
基 于 OpenMP 将 该 串 行 程 序 并 行 化 . 依 据 使 用 制 导 语 句 的 不 同 , 可 有 若<br />
干 种 方 法 ( 我 们 只 讨 论 基 于 刚 讲 过 的 并 行 区 与 for 结 构 ):<br />
仅 用 并 行 区 结 构 将 该 程 序 改 为 一 SPMD 并 行 程 序 .<br />
用 任 务 分 割 结 构 进 行 并 行 化 .<br />
归 约 .<br />
2006 年 4 月 共 享 存 储 编 程 75/108
串 行 程 序<br />
#include "stdio.h"<br />
main(int argc,char* argv[])<br />
{{<br />
…<br />
n = atoi(argv[1]);<br />
w = 1.0 1.0 //(double) n; n;<br />
sum sum = 0.0; 0.0;<br />
}}<br />
for(i=0;i
仅 基 于 Parallel 块 结 构 的 并 行 程 序<br />
#include #include"stdio.h"<br />
main(int main(intargc, argc, char char *argv[]){ *argv[]){<br />
…<br />
n n = atoi(argv[1]);<br />
w = 1.0 1.0 //(double) (double) n; n;<br />
sum sum = 0.0; 0.0;<br />
#pragma #pragmaomp ompparallel parallel private(x) shared(w) reduction(+:sum)<br />
{{<br />
myid myid = omp_get_thread_num();<br />
numthreads = omp_get_num_threads();<br />
for(i=myid;i
基 于 for 结 构 的 并 行 化 代 码<br />
#include #include"stdio.h"<br />
main(int main(intargc, argc, char char *argv[]) *argv[])<br />
{{<br />
…<br />
n = atoi(argv[1]);<br />
w = 1.0 1.0 //(double) (double) n; n;<br />
sum sum = 0.0; 0.0;<br />
#pragma omp ompfor for reduction(+:sum)<br />
for(i=0;i
OpenMP 结 构 化 块 类 型<br />
OpenMP 主 要 有 五 类 结 构 化 块 :<br />
并 行 区 Parallel Regions<br />
任 务 分 割 Worksharing<br />
数 据 环 境 Data Environment<br />
同 步 Synchronization<br />
运 行 时 函 数 / 环 境 变 量<br />
2006 年 4 月 共 享 存 储 编 程 79/108
OpenMP 同 步<br />
共 享 变 量 读 写<br />
单 一 文 件 I/O<br />
OpenMP 提 共 下 列 同 步 结 构 :<br />
– atomic<br />
– critical section<br />
– barrier<br />
– flush<br />
– ordered<br />
– single<br />
– master<br />
这 两 个 结 构 实 质 上 不 属 于 同 步 结<br />
构 , 是 并 行 区 结 构 和 任 务 分 割 结 构<br />
中 的 内 容 .<br />
2006 年 4 月 共 享 存 储 编 程 80/108
critical section<br />
同 时 至 多 有 一 个 线 程 进 入 临 界 区 .<br />
#pragma omp critical [(name)] new-line<br />
structured-block<br />
C$OMP PARALLEL DO PRIVATE(B)<br />
C$OMP& SHARED(RES)<br />
DO 100 I=1,NITERS<br />
B = DOIT(I)<br />
C$OMP CRITICAL<br />
CALL CONSUME (B, RES)<br />
C$OMP END CRITICAL<br />
100 CONTINUE<br />
2006 年 4 月 共 享 存 储 编 程 81/108
atomic<br />
Atomic 是 临 界 区 的 特 例 , 主 要 用 于 某 些 简 单 的 语 句 .<br />
#pragma omp atomic new-line<br />
expression-stmt<br />
其 中 expression-stmt 只 能 为 下 列 情 形 :<br />
⌧x binop = expr (bino 只 能 是 + * - / & ^ | > )<br />
⌧x++<br />
⌧++x<br />
⌧x--<br />
⌧--x<br />
仅 用 于 内 存 变 量 的 更 新 ( 在 下 面 的 例 子 中 即 对 X 的 更 新 )<br />
• C$OMP PARALLEL PRIVATE(B)<br />
• B = DOIT(I)<br />
• C$OMP ATOMIC<br />
• X = X + B<br />
• C$OMP END PARALLEL<br />
2006 年 4 月 共 享 存 储 编 程 82/108
下 面 两 段 代 码 区 别 是 什 么 ?<br />
#pragma omp parallel for \<br />
shared(x, y, index, n)<br />
for (i=0; i
原 子 操 作 和 临 界 区 比 较<br />
原 子 性 是 指 操 作 的 不 可 再 分 性 ,OpenMP 利 用 原 子 结 构 主<br />
要 是 用 于 防 止 多 线 程 对 内 存 的 同 一 地 址 的 并 发 写 .<br />
临 界 区 可 以 完 成 所 有 的 原 子 操 作 .<br />
原 子 结 构 可 更 好 被 编 译 优 化 :<br />
有 硬 件 指 令 可 用 于 实 现 原 子 操 作 , 而 且 系 统 开 销 也 很 小 .<br />
原 子 操 作 与 并 发 并 不 矛 盾 ,<br />
临 界 区 一 定 是 串 行 执 行 的 , 原 子 操 作 不 一 定 是 串 行 执 行<br />
2006 年 4 月 共 享 存 储 编 程 84/108
arrier<br />
Barrier: 每 一 线 程 等 待 直 至 所 有 组 内 其 它 线 程 执 行 到 Barrier 为 止 .<br />
#pragma omp parallel shared (A, B, C) private(id)<br />
{<br />
id=omp_get_thread_num();<br />
A[id] = big_calc1(id);<br />
#pragma omp barrier<br />
#pragma omp for<br />
for(i=0;i
ordered<br />
Ordered 用 于 指 定 循 环 中 各 线 程 执 行 任 务 的 顺 序 严 格 与 顺 序 方 式 时 的<br />
执 行 顺 序 一 致 .<br />
以 制 导 语 句 , 而 不 是 子 句 出 现 的 ordered, 只 能 出 现 在 并 行 区 动 态 范 围 内<br />
如 : 在 并 行 区 中 按 顺 序 方 式 打 印 输 出 :<br />
void worker(int k){<br />
#pragma omp ordered<br />
printf(“%d ”,k);<br />
}<br />
main(){<br />
int i;<br />
#pragma omp parallel for schedule(dynamic)<br />
for(i=0;i
master<br />
Master 结 构 用 于 标 志 一 个 结 构 块 只 能 由 主 线 程 执 行 . 其 它 线 程 跨 越 该<br />
块 . 该 结 构 无 隐 式 barrier 同 步 .<br />
#pragma omp parallel private (tmp)<br />
{<br />
}<br />
do_many_things();<br />
#pragma omp master<br />
{ exchange_boundaries(); }<br />
#pragma barrier<br />
do_many_other_things();<br />
2006 年 4 月 共 享 存 储 编 程 87/108
single<br />
Single 结 构 用 于 标 志 一 个 块 内 的 代 码 仅 能 由 一 个 线 程 执 行 ( 不 一 定 是 主 线<br />
程 ).<br />
在 single 块 后 有 一 隐 式 的 barrier 同 步 操 作 .<br />
#pragma omp ompparallel{<br />
最 早 遇 到<br />
#pragma omp ompsingle<br />
single 块<br />
者 执 行<br />
printf("Beginning work1.\n");<br />
work1();<br />
同 步<br />
#pragma omp ompsingle<br />
printf("Finishing work1.\n");<br />
同 步<br />
#pragma omp ompsingle nowait<br />
printf("Finished work1 and and beginning<br />
work2.\n");<br />
不 同 步<br />
work2();<br />
}}<br />
2006 年 4 月 共 享 存 储 编 程 88/108
flush<br />
#pragma omp flush [(list)] new-line<br />
!$OMP FLUSH [(list)]<br />
Flush 语 句 可 显 式 或 隐 式 执 行 . 用 于 在 程 序 的 某 一 点 处 , 确 定<br />
共 享 内 存 中 的 变 量 对 各 线 程 的 应 印 象 是 一 致 的 .<br />
如 : 编 译 器 必 须 将 寄 存 器 中 的 值 写 回 内 存 , 硬 件 刷 新 缓 冲<br />
区 等 .<br />
2006 年 4 月 共 享 存 储 编 程 89/108
Flush(Fortran)<br />
隐 式 flush<br />
BARRIER<br />
CRITICAL and END CRITICAL<br />
END DO<br />
END SECTIONS<br />
END SINGLE<br />
END WORKSHARE<br />
ORDERED and END ORDERED<br />
PARALLEL and END PARALLEL<br />
PARALLEL DO and END PARALLEL DO<br />
PARALLEL SECTIONS and END PARALLEL SECTIONS<br />
PARALLEL WORKSHARE and END PARALLEL WORKSHARE<br />
下 列 语 句 无 隐 式 flush<br />
DO<br />
MASTER and END MASTER<br />
SECTIONS<br />
SINGLE<br />
WORKSHARE<br />
2006 年 4 月 共 享 存 储 编 程 90/108
Flush(C)<br />
隐 式 flush<br />
barrier<br />
Critical 区 的 出 入 口<br />
Ordered 区 的 出 入 口<br />
Parallel 的 出 口<br />
For 的 出 口<br />
Sections 的 出 口<br />
Single 的 出 口<br />
无 隐 式 flush<br />
no wait<br />
2006 年 4 月 共 享 存 储 编 程 91/108
隐 式 同 步<br />
下 列 OpenMP 结 构 之 后 有 隐 式 Barrier:<br />
•end parallel<br />
•end do do (( 用 nowait 禁 止 ))<br />
•end sections (( 用 nowait 禁 止 ))<br />
•end critical<br />
•end single (( 用 nowait 禁 止 ))<br />
2006 年 4 月 共 享 存 储 编 程 92/108
Nesting<br />
并 行 结 构 的 嵌 套<br />
一 个 parallel 语 句 可 以 出 现 在 嵌 套 在 另 一 个 parallel 内 . 如 果 不 明 确 指 定<br />
嵌 套 并 行 性 , 则 该 并 行 区 的 线 程 组 只 由 当 前 的 线 程 组 成 , 否 则 , 该 并 行 区<br />
可 建 立 自 己 的 线 程 组 .<br />
同 一 parallel 内 的 for, sections, 和 single 语 句 不 允 许 相 互 嵌 套 .<br />
同 名 critical 语 句 不 允 许 相 互 嵌 套 .<br />
for, sections, 和 single 不 能 出 现 在 critical, ordered, 和 master 的 动 态 范<br />
围 中 .<br />
barrier 语 句 不 能 出 现 在 for, ordered, sections, single, master, 和 critical<br />
的 动 态 范 围 中 .<br />
master 不 能 出 现 在 for, sections, 和 single 的 动 态 范 围 内 .<br />
ordered 不 能 出 现 在 critical 的 动 态 范 围 内 .<br />
2006 年 4 月 共 享 存 储 编 程 93/108
OpenMP 结 构 化 块 类 型<br />
OpenMP 主 要 有 五 类 结 构 化 块 :<br />
并 行 区 Parallel Regions<br />
任 务 分 割 Worksharing<br />
数 据 环 境 Data Environment<br />
同 步 Synchronization<br />
运 行 时 函 数 / 环 境 变 量<br />
2006 年 4 月 共 享 存 储 编 程 94/108
OpenMP 函 数<br />
锁 函 数<br />
omp_init_lock(), omp_set_lock(), omp_unset_lock(),<br />
omp_test_lock(), omp_destroy_lock()<br />
运 行 时 环 境 函 数 :<br />
– 改 变 或 检 查 线 程 数<br />
omp_set_num_threads(), omp_get_num_threads(),<br />
omp_get_thread_num(), omp_get_max_threads()<br />
– 开 / 关 嵌 套 和 动 态 代 码<br />
omp_set_nested(), omp_set_dynamic(), omp_get_nested(),<br />
omp_get_dynamic()<br />
– 当 前 代 码 位 于 并 行 区 内 吗 ?<br />
omp_in_parallel()<br />
– 机 器 有 多 少 个 处 理 器 ?<br />
omp_get_num_procs()<br />
2006 年 4 月 共 享 存 储 编 程 95/108
例 : 锁 的 使 用<br />
下 面 的 例 子 是 用 来 显 示 锁 的 使 用 :<br />
锁 对 象 具 有 omp_lock_t, 在 锁 使 用 前 需 对 锁 进 行 初 始 化 :<br />
omp_init_lock().<br />
当 一 个 线 程 试 图 获 得 锁 以 进 入 第 一 个 临 界 区 时 , 处 理 于 空 闲 状 态 , 以<br />
等 待 进 入 临 界 区 .<br />
一 旦 得 到 锁 , 则 对 临 界 区 加 锁 : omp_set_lock(), 退 出 完 临 界 区 时<br />
解 锁 omp_unset_lock().<br />
在 进 入 第 二 个 临 界 区 时 , 则 通 过 非 阻 塞 函 数 omp_test_lock() 来<br />
测 试 可 能 性 , 同 时 做 一 些 其 它 的 事 情 .<br />
在 锁 不 再 使 用 时 , 用 omp_destroy_lock() 销 毁 .<br />
2006 年 4 月 共 享 存 储 编 程 96/108
#include <br />
int main()<br />
{<br />
omp_lock_t lck;<br />
int id;<br />
omp_init_lock(&lck);<br />
#pragma omp parallel shared(lck) private(id)<br />
{<br />
id = omp_get_thread_num();<br />
omp_set_lock(&lck);<br />
printf("My thread id is %d.\n", id);<br />
omp_unset_lock(&lck);<br />
while (! omp_test_lock(&lck)) {<br />
skip(id); /* we do not yet have the lock, so we must do something else */<br />
}<br />
work(id); /* we now have the lock and can do the work */<br />
omp_unset_lock(&lck);<br />
}<br />
omp_destroy_lock(&lck);<br />
}<br />
2006 年 4 月 共 享 存 储 编 程 97/108
锁 : 保 护 共 享 资 源<br />
omp_lock_t lck; lck;<br />
omp_init_lock(&lck);<br />
#pragma omp ompparallel private (tmp)<br />
{<br />
id id = omp_get_thread_num();<br />
tmp tmp = do_lots_of_work(id);<br />
omp_set_lock(&lck);<br />
printf(“%d %d”, %d”, id, id, tmp);<br />
omp_unset_lock(&lck);<br />
}<br />
2006 年 4 月 共 享 存 储 编 程 98/108
设 定 动 态 模 式 , 由 程 序 来 指 定 线 程 数 ( 一 般 默 认 线 程 数 与 处 理 器 个 数 相 等 ).<br />
#include <br />
void void main()<br />
{<br />
omp_set_dynamic(0);<br />
omp_set_num_threads(4);<br />
#pragma omp ompparallel<br />
{<br />
int intid=omp_get_thread_num();<br />
do_lots_of_stuff(id);<br />
}<br />
}<br />
2006 年 4 月 共 享 存 储 编 程 99/108
指 定 线 程 数<br />
omp_set_dynamic(0);<br />
omp_set_num_threads(16);<br />
#pragma omp parallel shared(x, npoints) private(iam, ipoints)<br />
{<br />
if (omp_get_num_threads() != 16) abort();<br />
iam = omp_get_thread_num();<br />
ipoints = npoints/16;<br />
do_by_16(x, iam, ipoints);<br />
}<br />
2006 年 4 月 共 享 存 储 编 程 100/108
得 到 线 程 数<br />
int numthreads;<br />
numthreads = omp_get_num_threads();<br />
printf(“%d\n”,numthreads);<br />
#pragma omp parallel private(i)<br />
{<br />
numthreads = omp_get_num_threads();<br />
printf(“%d\n”,numthreads);<br />
}<br />
运 行 :<br />
1<br />
4<br />
4<br />
4<br />
4<br />
2006 年 4 月 共 享 存 储 编 程 101/108
环 境 变 量<br />
线 程 任 务 调 度 控 制<br />
– OMP_SCHEDULE “SCHEDULE[, CHUNK_SIZE]”<br />
设 定 缺 省 线 程 数<br />
– OMP_NUM_THREADS INT_LITERAL<br />
是 否 允 许 各 并 行 区 内 线 程 数 目 不 相 同 ( 动 态 生 成 线 程 组 )?<br />
– OMP_DYNAMIC TRUE || FALSE<br />
动 态 模 式 ( 默 认 ):<br />
⌧ 并 行 区 中 的 线 程 数 动 态 确 定 , 各 并 行 区 可 具 有 不 同 的 线 程 数 .<br />
⌧ 此 时 , 线 程 数 设 置 函 数 omp_set_num_threads() 只 设 定 一 上 限 , 实<br />
际 中 发 生 的 线 程 数 可 能 要 比 我 们 设 置 的 数 目 少 .<br />
静 态 模 式 :<br />
⌧ 由 程 序 员 确 定 并 行 区 中 线 程 的 数 量 .<br />
嵌 套 并 行 区 是 否 建 立 新 的 线 程 组 或 它 们 是 否 要 串 行 化 ?( 仅 由 线 程 组 中 的 主 线<br />
程 执 行 , 如 I/O 操 作 等 )<br />
– OMP_NESTED TRUE || FALSE( 默 认 为 FALSE)<br />
2006 年 4 月 共 享 存 储 编 程 102/108
汇 总<br />
并 行 区<br />
parallel<br />
任 务 分 割<br />
for<br />
sections<br />
Single<br />
parallel for<br />
parallel sections<br />
同 步<br />
master<br />
critical<br />
barrier<br />
atomic<br />
flush<br />
ordered<br />
<br />
<br />
<br />
<br />
<br />
<br />
并 行 区<br />
parallel<br />
任 务 分 割<br />
DO<br />
SECTIONS<br />
SINGLE<br />
WORKSHARE<br />
PARALLEL DO<br />
PARALLEL SECTIONS<br />
PARALLEL WORKSHARE<br />
同 步<br />
MASTER<br />
CRITICAL<br />
BARRIER<br />
ATOMIC<br />
FLUSH<br />
ORDERED<br />
2006 年 4 月 共 享 存 储 编 程 103/108
运 行 环 境 函 数 汇 总<br />
omp_set_num_threads<br />
omp_get_num_threads<br />
omp_get_max_threads<br />
omp_get_thread_num<br />
omp_get_num_procs<br />
omp_in_parallel<br />
omp_set_dynamic<br />
omp_get_dynamic<br />
omp_set_nested<br />
omp_get_nested<br />
OMP_SET_NUM_THREADS<br />
OMP_GET_NUM_THREADS<br />
OMP_GET_MAX_THREADS<br />
OMP_GET_THREAD_NUM<br />
OMP_GET_NUM_PROCS<br />
OMP_IN_PARALLEL<br />
OMP_SET_DYNAMIC<br />
OMP_GET_DYNAMIC<br />
OMP_SET_NESTED<br />
OMP_GET_NESTED<br />
OMP_GET_WTIME<br />
OMP_GET_WTICK<br />
2006 年 4 月 共 享 存 储 编 程 104/108
锁 函 数 汇 总<br />
omp_init_lock<br />
omp_init_nest_lock<br />
omp_destroy_lock<br />
omp_destroy_nest_lock<br />
omp_set_lock<br />
omp_set_nest_lock<br />
omp_unset_lock<br />
omp_unset_nest_lock<br />
omp_test_lock<br />
omp_test_nest_lock<br />
OMP_INIT_LOCK<br />
OMP_INIT_NEST_LOCK<br />
OMP_DESTROY_LOCK<br />
OMP_DESTROY_NEST_LOCK<br />
OMP_SET_LOCK<br />
OMP_SET_NEST_LOCK<br />
OMP_UNSET_LOCK<br />
OMP_UNSET_NEST_LOCK<br />
OMP_TEST_LOCK<br />
OMP_TEST_NEST_LOCK<br />
2006 年 4 月 共 享 存 储 编 程 105/108
环 境 变 量 (C 和 Fortran 一 样 )<br />
OMP_SCHEDULE<br />
OMP_NUM_THREADS<br />
OMP_DYNAMIC<br />
OMP_NESTED<br />
2006 年 4 月 共 享 存 储 编 程 106/108
OpenMP 特 点 总 结<br />
支 持 C,C++ 和 Fortran<br />
共 享 存 储 并 行 机 并 行 编 程 的 主 流 平 台 , 获 得 并 行 机 厂 商 和<br />
用 户 的 广 泛 支 持<br />
特 别 适 合 于 串 行 程 序 的 逐 步 并 行 化<br />
如 : 先 进 行 一 些 特 别 耗 时 的 大 循 环 的 并 行 化 , 然 后 再<br />
逐 步 进 行 再 大 粒 度 的 并 行 .<br />
Orphan 制 导 语 句 的 支 持 , 使 得 OpenMP 较 之 于 以 前 的<br />
共 享 存 储 编 程 模 型 更 适 合 粗 粒 度 的 并 行<br />
2006 年 4 月 共 享 存 储 编 程 107/108
谢<br />
谢 !<br />
2006 年 4 月 共 享 存 储 编 程 108/108