同步构造
- 考虑一个简单的示例,在两个不同处理器上的两个线程试图同时增加变量x的值(假定x被初始化为0):
THREAD 1:
increment(x) { x = x + 1; } THREAD 1:
10 LOAD A, (x address) 20 ADD A, 1 30 STORE A, (x address) |
THREAD 2:
increment(x) { x = x + 1; } THREAD 2:
10 LOAD A, (x address) 20 ADD A, 1 30 STORE A, (x address) |
- 一种可能出现的执行顺序:
1. 线程一加载x到寄存器A
2. 线程二加载x到寄存器A
3. 线程一将寄存器A的值+1
4. 线程二将寄存器A的值+1
5. 线程一将寄存器A的值保存到x
6. 线程二将寄存器A的值保存到x
结果将会是1,而不是期望的2.(注:两个cpu,所以"寄存器 A"不是同一个)
- 要避免这种情况,两个线程对x的增加操作必须同步来保证得到正确的结果
- OpenMP提供了几种同步构造来控制一个线程处理与其他线程相关的执行
同步构造
MASTER 指令
目的:
- MASTER指令指定一个只能被主线程执行的区域,其他的线程都将忽略这块代码区域
- 这条指令没有相关隐式关卡
格式:
Fortran |
!$OMP MASTER
block
!$OMP END MASTER |
C/C++ |
#pragma omp master newline
structured_block |
限制:
- 扩充MASTER 块是非法的
CRITICAL 指令
目的:
- CRITICAL指令指定一块同一时间只能被一条线程执行的代码区域
格式:
Fortran |
!$OMP CRITICAL [ name ]
block
!$OMP END CRITICAL |
C/C++ |
#pragma omp critical [ name ] newline
structured_block |
注意:
- 如果一条线程正在一个CRITICAL区域执行而另一个线程到达这个区域,并企图执行,那么它将会被阻塞,直到第一个线程离开这个区域.
- 命名是可选项,使不同的CRITICAL区域共存:
- 命名是全局标志符.具有相同命名的不同的CRITICAL区域被当作同一个区域
- 所有未命名CRITICAL区域被当作同一个区域
限制:
- 扩充CRITICAL 块是非法的.
Example: CRITICAL Construct
- 所有的线程试图并行执行,但由于对x增加的代码被CRITICAL构造包围,在任何时刻均只能有一个线程对此进行读/增加/写操作
Fortran - CRITICAL Directive Example
PROGRAM CRITICAL
INTEGER X X = 0
!$OMP PARALLEL SHARED(X)
!$OMP CRITICAL X = X + 1 !$OMP END CRITICAL
!$OMP END PARALLEL
END |
C / C++ - critical Directive Example
#include <omp.h>
main() {
int x; x = 0;
#pragma omp parallel shared(x) {
#pragma omp critical x = x + 1;
} /* end of parallel section */
} |
BARRIER 指令
目的:
- BARRIER指令同步线程组中的所有线程
- 到达一个BARRIER指令后,线程会原地等待其他的线程,然后恢复并行执行其后的代码
格式:
Fortran |
!$OMP BARRIER |
C/C++ |
#pragma omp barrier newline |
限制:
- 线程组中的所有线程都将执行(不执行)BARRIER区域
- 线程组中的所有线程遇到的work-sharing区域和barrier区域的顺序必须统一
TASKWAIT 指令
目的: