开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第5天,点击查看活动详情
OpenMP是一个面向共享存储的多CPU多线程并行编程接口。
共享存储是指所有CPU不需要网络连接而访问到同一块内存。所以OpenMP只局限于在单机之中进行并行。
目前混合并行编程都是通过OpenMP和MPI共同完成,其中MPI(消息传递接口)封装了socket,它能通过网络
连接在不同节点之间进行数据通信和共享。
OpenMP是fork-join模型
在我们使用OpenMP编写一个C程序时,有串行的程序块,也有并行的程序块。
进入main函数,主线程(master thread)会从上往下运行串行块,当碰到并行程序时,
它会fork出许多子线程去执行不同的任务,等到所有的子线程都完成时(这里有同步机制)再join,
join之后是主线程在运行。再碰到并行块的时候会再fork。
OpenMP的构成
- 编译指导语句
- 运行时库函数(Runtime Library)
- 环境变量
编译指导语句格式
#pragma omp <directive> [clause, ...]
注意它是以注释的方式出现的,如果正常gcc编译则会将其看成注释,得到的是一个串行程序,如果加上-fopenmp则会编译程并行程序
常用的directive
- parallel:用在并行结构块之前,表示要并行
- for:用在for循环之前,openmp会自动分配数据且并行化处理,它默认数据列表是私有的
- sections:可并行执行的代码段各自用section标出
- criticial :表示临界区
- single :用在并行区域中,表示只被一个线程执行
- flush : 刷新
- barrier :栅栏,用来同步,碰到栅栏,所有程序都执行到barrier才能继续往下执行。
常用的clause
- private:声明后面的变量是线程私有的
- shared:声明后面的变量是所有线程共享的
- default:设置默认下变量的共享属性,有shared和none,none是指不启用默认
- firtstprivate:首先它是私有变量,但其初始值是主线程中同名变量的值
- lastprivate:私有变量,将最后一个线程中变量的结果复制到主线程的同名变量中
- reduction:指定哪些变量在并行处理结束后需要做规约(求向量所有元素的和就是典型 的规约操作)
- copyin:指定一个threadprivate变量需要用主线程同名变量进行初始化
简单示例1
hello_omp.c
#include <omp.h>
#include <stdio.h>
int main(int argc, char *argv[]) {
int nthreads, tid;
/* Fork a team of threads giving them their own copies of variables */
#pragma omp parallel private(nthreads, tid)
{
/* Obtain thread number */
tid = omp_get_thread_num();
nthreads = omp_get_num_threads();
printf("Hello World from thread %d of %d\n", tid, nthreads);
}
}
gcc编译
gcc -fopenmp hello_omp.c -o hello_omp
运行结果:
Hello World from thread 3 of 8
Hello World from thread 0 of 8
Hello World from thread 6 of 8
Hello World from thread 2 of 8
Hello World from thread 4 of 8
Hello World from thread 1 of 8
Hello World from thread 7 of 8
Hello World from thread 5 of 8
简单示例2
#include <omp.h>
#include <stdio.h>
int main(int argc, char *argv[]) {
int sum = 0;
int array[10] = {1,2,3,4,5,6,7,8,9,10};
#pragma omp parallel for /*for中的迭代变量i默认是私有的*/
for (int i = 0; i < 10; i++) {
sum += array[i];
}
printf("sum = %d", sum);
return 0;
}
运行结果
sum = 55