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

#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[], NULL, );
#pragma omp parallel num_threads(thread_count)
Hello(); return ;
} 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语法中,执行并行块的线程集合(原始线程和新的线程被称为线程组,原始的线程被称为主线程,额外的线程称为从线程。每个线程组成员都调用指令后的代码块。

# pragma omp parallel num_threads ( thread_count )

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

#include <omp.h>

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

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

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

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

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

  • eg:梯形积分法

如果每个子区间有相同的宽度,并且定义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 = ; i <= n-; i++) {
x_i = a + ih;
approx += f(x_i);
}
approx = h*approx;

第一种尝试:1) 定义两种类型的任务:

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

    b) 将面积加起来。

2) 在第一阶段,没有通信开销;但第二阶段每个任务需要通信。考虑一个问题:结果不可预估——引入互斥量

# 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[], NULL, );
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 ;
} /∗ 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 = ; i <= local_n−; i++){
x = local_a + i*h;
my_result += f(x);
}
` ` my_result = my_result*h;
# pragma omp critical
∗global_result_p += my_result;
} /∗ Trap ∗/

规约从句

替代(在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 = ; i <= n−; 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 = ; k < n; k++){
if (k % == )
factor = 1.0;
else
factor = −1.0;
sum += factor/(∗k+);
}

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

#  pragma omp for

解决循环调用问题:

schedule ( type , chunksize )
//chunksize 是一个正整数

type 可以是:

static: 提前把任务分配好;

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

dynamic:任务被分成 chunksize 大小的连续段;每个线程执行一小块, 当有一个线程执行完时, 它会请求获得1个新的;重复上述过程,直到完成计算;

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

guided:每个线程执行一小块, 当有一个线程执行完时, 它会请求获得1个新的;但是,新的任务块是不断变小的;如果不指定chunksize,那么默认会降到1.如果指定了chunksize, 则会降到指定的chunksize, 除了最后一块可能小于chunksize.

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

runtime: 运行时决定。

使用openmp进行共享内存编程的更多相关文章

  1. Linux共享内存编程实例

    /*共享内存允许两个或多个进程进程共享同一块内存(这块内存会映射到各个进程自己独立的地址空间) 从而使得这些进程可以相互通信. 在GNU/Linux中所有的进程都有唯一的虚拟地址空间,而共享内存应用编 ...

  2. Linux 共享内存编程

    共享内存允许系统内两个或多个进程共享同一块内存空间,并且数据不用在客户进程和服务器进程间复制,因此共享内存是通信速度最快的一种IPC. 实现的机制简单描述如下:一个进程在系统中申请开辟了一块共享内存空 ...

  3. System V IPC 之共享内存

    IPC 是进程间通信(Interprocess Communication)的缩写,通常指允许用户态进程执行系列操作的一组机制: 通过信号量与其他进程进行同步 向其他进程发送消息或者从其他进程接收消息 ...

  4. Linux进程间通信—共享内存

    五.共享内存(shared memory) 共享内存映射为一段可以被其他进程访问的内存.该共享内存由一个进程所创建,然后其他进程可以挂载到该共享内存中.共享内存是最快的IPC机制,但由于linux本身 ...

  5. Linux共享内存(二)

    Linux共享内存编程实例 原文链接:http://blog.csdn.net/pcliuguangtao/article/details/6526119 /*共享内存允许两个或多个进程进程共享同一块 ...

  6. Linux进程间通信 共享内存+信号量+简单样例

    每个进程都有着自己独立的地址空间,比方程序之前申请了一块内存.当调用fork函数之后.父进程和子进程所使用的是不同的内存. 因此进程间的通信,不像线程间通信那么简单.可是共享内存编程接口能够让一个进程 ...

  7. 转:Linux--进程间通信(信号量,共享内存)

    源地址:http://www.cnblogs.com/forstudy/archive/2012/03/26/2413724.html Linux--进程间通信(信号量,共享内存)(转)   一. 信 ...

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

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

  9. linux编程之共享内存

    linux 进程间通信(IPC)包括3种机制:消息队列.信号量.共享内存.消息队列和信号量均是内核空间的系统对象,经由它们 的数据需要在内核和用户空间进行额外的数据拷贝:而共享内存和访问它的所有应用程 ...

随机推荐

  1. iOS 应用签名

    一.密码学简介 1.1 base64 Base64 是一种通过查表的编码方法,不能用于加密,即使使用自定义的编码表也不行. Base64 适用于小段内容的编码,比如数字证书签名.Cookie 的内容等 ...

  2. IEnumerable和IQueryable在使用时的区别

    最近在调研数据库查询时因使用IEnumerable进行Linq to entity的操作,造成数据库访问缓慢.此文讲述的便是IEnumerable和IQueryable的区别. 微软对IEnumera ...

  3. 《Flutter 动画系列》组合动画

    老孟导读:在前面的文章中介绍了 <Flutter 动画系列>25种动画组件超全总结 http://laomengit.com/flutter/module/animated_1/ < ...

  4. Python——五分钟理解函数式编程与闭包

    本文始发于个人公众号:TechFlow,原创不易,求个关注 今天是Python专题的第9篇文章,我们来聊聊Python的函数式编程与闭包. 函数式编程 函数式编程这个概念我们可能或多或少都听说过,刚听 ...

  5. 200行PYTHON代码实现贪吃蛇

    200行Python代码实现贪吃蛇 话不多说,最后会给出全部的代码,也可以从这里Fork,正文开始: 目前实现的功能列表: 贪吃蛇的控制,通过上下左右方向键: 触碰到边缘.墙壁.自身则游戏结束: 接触 ...

  6. Pyhton多线程

    在了解多线程前先给大家介绍下并发和并行: 并发:多个任务一起执行 在多任务之间快速切换处理 任务数量大于cpu核数  并行:一个cpu核处理一个任务,多个cpu核同时处理多个任务 任务数量等于或者小于 ...

  7. Linux学习第10天-命令执行顺序控制与管道

    学习重点: cut,grep,wc,sort命令的使用 管道的理解 一.顺序执行多条命令 当我们需要使用apt-get安装一个软件,然后安装完成后立即运行安装的软件(或命令工具),又恰巧你的主机才更换 ...

  8. 记录一次简单的springboot发送邮件功能

    场景:经常在我们系统中有通过邮件功能找回密码,或者发送生日祝福等功能,今天记录下springboot发送邮件的简单功能 1.引入maven <!-- 邮件开发--><dependen ...

  9. 天天写order by,你知道Mysql底层执行原理吗?

    前言 文章首发于微信公众号[码猿技术专栏]. 在实际的开发中一定会碰到根据某个字段进行排序后来显示结果的需求,但是你真的理解order by在 Mysql 底层是如何执行的吗? 假设你要查询城市是苏州 ...

  10. MODIS系列之NDVI(MOD13Q1)三:.jdk文件配置+MRT安装

    MRT(MODIS Reprojection Tool)简介: MODIS的全称为中分辨率成像光谱仪(Moderate-Resolution Imaging Spectroradiometer),是搭 ...