预处理指令pragma

在系统中加入预处理器指令一般是用来允许不是基本c语言规范部分的行为。不支持pragma的编译器会忽略pragma指令提示的那些语句,这样就允许使用pragma的程序在不支持它们的平台上运行。

第一个程序:hello

#include <stdio.h>
#include <stdlib.h>
#include <omp.h> void Hello(void); // Thread function int main(int argc, char* argv[]) { 
// Get number of threads from command line 
int thread_count = strtol(argv[1], NULL, 10);
#pragma omp parallel num_threads(thread_count) 
Hello();
  return 0;
} void Hello(void) {
int my_rank = omp_get_thread_num();
int thread_count = omp_get_num_threads(); printf("Hello from thread %d of %dnn\n", my_rank, thread_count);
}

Hello例子的分析:

最基本的并行原语

用于运行代码块的线程数可以动态生成。

pragma omp parallel  :

当程序到达parallel指令时,原来的线程继续执行,另外的线程被启动。在openmp语法中,执行并行块的线程集合(原始线程和新的线程被称为线程组,原始的线程被称为主线程,额外的线程称为从线程。每个线程组成员都调用指令后的代码块。

num_thread( )

# pragma omp parallel num_threads ( thread_count )

一个从句例子(用于修饰原语),可用于指定线程数量

omp.h

#include <omp.h>

使用openmp必须含omp.h头文件

strtol( )

long strtol(const char* number p,char** end p,int base);

使用stdlib.h中的strtol来获得线程数

ps:一些系统因素可能会限制可以启动的线程数量;OpenMP 并不保证能够启动指定个的线程;

多数系统能够启动上百甚至上千的线程;除非启动的太多,一般都能满足要求。

例子:梯形积分法

如果每个子区间有相同的宽度,并且定义h=(b-a)/n,xi=a+ih,i=0, 1, ..., n,那么近似值将是:

 //串行算法实现//
Input: a, b, n ;
h = (b*a)/n;
approx = (f(a) + f(b))/2.0;
for (i = 1; i <= n-1; i++) {
x_i = a + i*h;
approx += f(x_i);
}
approx = h*approx;

第一种尝试

  1. 定义两种类型的任务:

​ a) 计算单个梯形的面积;

​ b) 将面积加起来。

  1. 在第一阶段,没有通信开销;但第二阶段每个任务需要通信。

考虑一个问题:结果不可预估——引入互斥量

pragma omp critical   global_result += my_result ;

第一个版本

 #include <stdio.h>
 #include <stdlib.h>
#include <omp.h> void Trap(double a, double b, int n, double  global_result p);
int main(int argc, char  argv[]){
double  global_result = 0.0;
double  a, b;
int     n;
int     thread_count; thread_count = strtol(argv[1], NULL, 10);
printf("Enter a, b, and n n");
scanf("%lf %lf %d", &a, &b, &n);
#  pragma omp parallel num_threads(thread_count)
Trap(a, b, n, &global_result); printf("With n = %d trapezoids, our estimate n", n);
printf("of the integral from %f to %f = %.14e n",
a, b, global_result);
return 0;
}    /∗  main ∗/  void Trap(double a, double b, int n, double* global_result_p)
double  h, x, my_result;
double  local_a, local_b;
int  i, local n;
int my_rank = omp_get_thread_num();
int thread_count = omp_get_num_threads(); h = (b−a)/n;
local_n = n/thread_count;
local_a = a + my_rank*local_n*h;
local_b = local_a + local_n*h;
my_result = (f(local_a) + f(local_b))/2.0;
for (i = 1; i <= local_n−1; i++){
x = local_a + i*h;
my_result += f(x);
}
` ` my_result = my_result*h;
#  pragma omp critical
∗global_result_p += my_result;
}    /∗  Trap ∗/

作用域

在串行程序中, 变量的作用域包含了所有可以使用变量的区域;

在OpenMP中, 变量的作用域还要包括可以访问该变量的并行区域。

能被所有线程访问的变量具有 shared(共享) 作用域;

只能被一个线程访问的变量具有 private (私有)作用域.

默认的作用域是 shared.

规约从句:

替代(在parallel块中声明一个私有变量和将临界区移到函数调用之)

归约:将相同的归约操作符重复的应用到操作数序列来得到一个结果的计算。

所有操作的中间结果存储在一个变量中:归约变量

reduction(<operator>:<variable list>)

新的代码:

global_result = 0.0;
#  pragma omp parallel num threads(thread count)\
reduction(+: global_result)
global_result += Local_trap(double a, double b, int n);

parallel for

能够生成一队线程来执行接下来的语句块;

语句块必须是一个for循环;

通过将循环切分给不同的线程来实现并行。

只有迭代次数确定的循环才可以被并行化。

h = (b−a)/n;
approx = (f(a) + f(b))/2.0;
#  pragma omp parallel for num threads(thread_count) reduction(+: approx)
for (i = 1; i <= n−1; i++)
approx += f(a + i∗h); approx = h∗approx;

可被并行化的for循环形式:

**ps: **index 必须是整数或者指针 (e.g., 不能是浮点数);

start, end, 和 incr 必须具有相应的类型。 例如, 如果index 是一个指针, 那么 incr 必须是一个整型;

start, end, 和 incr 在循环执行过程中不能被修改;

在循环执行过程中, 变量 index 只能被for语句修改。

数据依赖

1.OpenMP 编译器并不检查循环迭代中的数据依赖问题;

2.一般来说,OpenMP无法处理带有数据依赖的循环。

解决思路:设计私有变量并且保证其私有作用域(private子句)

default子句

编译器强制要求程序员指定在块中使用的外部变量的作用范围。

double sum = 0.0;
# pragma omp parallel for num threads(thread count)\
default(none) reduction(+:sum) private(k, factor)\
shared(n)
for (k = 0; k < n; k++){
if (k % 2 == 0)
factor = 1.0;
else
factor = −1.0;
sum += factor/(2∗k+1);
}

for指令

并不创建线程,使用已经在parallel块中创建的线程。

#  pragma omp for

解决循环调用问题:schedule ( type , chunksize )

type 可以是:

static: 提前把任务分配好;

dynamic or guided: 在运行时动态分配;

dynamic:

任务被分成 chunksize 大小的连续段;

每个线程执行一小块, 当有一个线程执行完时, 它会请求获得1个新的;

重复上述过程,直到完成计算;

chunksize 可以被去掉;当去掉时, chunksize 默认为1.

guided:

每个线程执行一小块, 当有一个线程执行完时, 它会请求获得1个新的;

但是,新的任务块是不断变小的;

如果不指定chunksize,那么默认会降到1.

如果指定了chunksize, 则会降到指定的chunksize, 除了最后一块可能小于chunksize.

auto: 编译器或者运行时系统决定调度策略;

runtime: 运行时决定。

chunksize 是一个正整数

使用openmp进行并行编程的更多相关文章

  1. C++ OpenMp的并行编程

    基于OpenMp的并行编程 功能:并行处理比较耗时的for循环 在OpenMP中,对for循环并行化的任务调度使用schedule子句来实现: 使用格式:schedule(type[,size]) t ...

  2. 【并行计算】基于OpenMP的并行编程

    我们目前的计算机都是基于冯偌伊曼结构的,在MIMD作为主要研究对象的系统中,分为两种类型:共享内存系统和分布式内存系统,之前我们介绍的基于MPI方式的并行计算编程是属于分布式内存系统的方式,现在我们研 ...

  3. OpenMP共享内存并行编程详解

    实验平台:win7, VS2010 1. 介绍 平行计算机可以简单分为共享内存和分布式内存,共享内存就是多个核心共享一个内存,目前的PC就是这类(不管是只有一个多核CPU还是可以插多个CPU,它们都有 ...

  4. OpenMP并行编程

    什么是OpenMP?“OpenMP (Open Multi-Processing) is an application programming interface (API) that support ...

  5. OpenMP并行编程应用—加速OpenCV图像拼接算法

    OpenMP是一种应用于多处理器程序设计的并行编程处理方案,它提供了对于并行编程的高层抽象.仅仅须要在程序中加入简单的指令,就能够编写高效的并行程序,而不用关心详细的并行实现细节.减少了并行编程的难度 ...

  6. OpenMP 并行编程

    OpenMP 并行编程 最近开始学习并行编程,目的是为了提高图像处理的运行速度,用的是VS2012自带的OpenMP. 如何让自己的编译器支持OpenMP: 1) 点击 项目属性页 2)点击 配置 3 ...

  7. 并行编程OpenMP基础及简单示例

    OpenMP基本概念 OpenMP是一种用于共享内存并行系统的多线程程序设计方案,支持的编程语言包括C.C++和Fortran.OpenMP提供了对并行算法的高层抽象描述,特别适合在多核CPU机器上的 ...

  8. 在C++中使用openmp进行多线程编程

    在C++中使用openmp进行多线程编程 一.前言 多线程在实际的编程中的重要性不言而喻.对于C++而言,当我们需要使用多线程时,可以使用boost::thread库或者自从C++ 11开始支持的st ...

  9. C#并行编程系列-文章导航

    菜鸟初步学习,不对的地方请大神指教,参考<C#并行编程高级教程.pdf> 目录 C#并行编程-相关概念 C#并行编程-Parallel C#并行编程-Task C#并行编程-并发集合 C# ...

随机推荐

  1. office2010安装与破解,笔者亲测可用!!!!!!

    我们首先需要准备office2010安装包与破相应的破解软件.软件包的获取方式:扫码关注[猿成长],,回复 office2010安装,即可获取,下载解压后文件目录结构如下图所示: 打开安装程序文件夹, ...

  2. 5.Maven坐标

    而这个坐标也意味着jar包等保存在 C:\Users\用户名.m2\repository\org\apache\tomcat\tomcat-catalina\9.0.2

  3. ARDUINO UNO数字引脚端口上电后不稳定状态。

    ARDUINO UNO数字引脚端口上电后不稳定状态. 在使用4*4矩阵键盘时,遇到了输入端的电平无法稳定,一直被识别为高电平. 在发现这一问题后,首先检查程序是否出错.检查后发现程序没有任何问题. 于 ...

  4. [vijos1782]借教室<线段树>

      题目链接:https://vijos.org/p/1782 题意:一个区间1,n.m次操作,每次操作让l,r区间值减去d,当有任何一个值小于0就输出当前是第几个操作 这道题其实是没有什么难度的,是 ...

  5. MySQL默认隔离级别为什么是RR

    曾多次听到“MySQL为什么选择RR为默认隔离级别”的问题,其实这是个历史遗留问题,当前以及解决,但是MySQL的各个版本沿用了原有习惯.历史版本中的问题是什么,本次就通过简单的测试来说明一下. 1. ...

  6. Mob之社会化分享集成ShareSDK

    接着上篇顺便分享一篇自己使用 ShareSDK 的笔记,上篇我们集成了 SMSSDK 完成了短信接收验证码的功能,请参考Mob 之 短信验证集成 SMSSDK,如何在项目已经集成 SMSSDK 的情况 ...

  7. RocketMQ的高可用集群部署

    RocketMQ的高可用集群部署 标签(空格分隔): 消息队列 部署 1. RocketMQ 集群物理部署结构 Rocket 物理部署结构 Name Server: 单点,供Producer和Cons ...

  8. PTA数据结构与算法题目集(中文) 7-41PAT排名汇总 (25 分)

    PTA数据结构与算法题目集(中文)  7-41PAT排名汇总 (25 分) 7-41 PAT排名汇总 (25 分)   计算机程序设计能力考试(Programming Ability Test,简称P ...

  9. css布局之盒模型

    盒模型 导读 随着网络技术的不断发展,人们已经不再只关注网页的功能,还追求网页的性能和美观,于是css应运而生,一个完美的网页必然有一个完美的布局,而css盒模型是网页布局的基石,所以了解它对网页制作 ...

  10. Redis 笔记(六)—— ZSET 常用命令

    常用命令 命令 用例和描述 ZADD ZADD key-name score member [score member ...] —— 将带有分值的成员添加到 HSET 中 ZREM ZREM key ...