OpenMP 作业

        openMP是基于共享内存的编程模型,其编程是对线程来说的,就是基于编译器对omp的编译指导语句来编写的并行程序,其最大的好处是屏蔽掉多线程的底层细节,可以较快的把串行执行的程序通过少量的修改变成多线程程序。当然它的劣势很明显,只能够线程并行,而且调试起来麻烦,并不适合多机器分布的多任务之间的并行。

OMP  包含编译制导(Compiler Directive)、运行库例程(Runtime Library)和环境变量(Environment Variables)三部分。

OpenMP采用Fork-Join并行执行方式。


      下面是一些omp语法的介绍,其中比较难的是对程序的并行划分,和数据依赖的处理。数据依赖分为:读后写,写后读和写后写的情况。这点和数据库的要保持数据的一致性蛮像的。


parallel语句结构

并行域中的代码被所有的线程执行,相当于有N个线程,都执行这个并行域中的代码。

#pragma omp parallel [clause[[,]clause]…]newline

  • clause=
  • if (scalar_expression)
  • private (list)
  • shared (list)
  • default (shared | none)
  • firstprivate (list)
  • reduction (operator: list)
  • copyin (list) 


  • for 语句结构
  • for 用于for循环之前,将循环分配到多个线程中并行执行,必须保证每 次循环之间无相关性。 
  • parallel forparallel 
  • 和for语句的结合,也是用在一个for循环之前,表示for 循环的代码将被多个线程并行执行。 
  • sections 用在可能会被并行执行的代码段之前 parallel sections parallel和sections两个语句的结合 
  • critical 用在一段代码临界区之前 
  • single 用在一段只被单个线程执行的代码段之前,表示后面的代码段将 被单线程执行 
  • barrier,用于并行区内代码的线程同步,所有线程执行到barrier时要停止 直到所有线程都执行到barrier时才继续往下执行。 
  • Atomic 用于指定一块内存区域被制动更新 
  • Master 用于指定一段代码块由主线程执行 
  • Ordered 用于指定并行区域的循环按顺序执行 
  • threadprivate用于指定一个变量是线程私有


OpenMP除上述指令外,还有一些库函数,下面列出几个常用的库函数

  • omp_get_num_procs, 返回运行本线程的多处理机的处理器个数。
  • omp_get_num_threads, 返回当前并行区域中的活动线程个数。 
  • omp_get_thread_num, 返回线程号 omp_set_num_threads, 设置并行执行代码的线程个数 
  • omp_init_lock, 初始化一个简单锁 
  • omp_set_lock,上锁操作 
  • omp_unset_lock,解锁操作,要和omp_set_lock函数配对使用。 
  • omp_destroy_lock,omp_init_lock函数的配对操作函数,关闭一个锁


OMP的子句还有如下一些

  • private, 指定每个线程都有它自己的变量私有副本。 
  • firstprivate,指定每个线程都有它自己的变量私有副本,并且变量要被 继承主线程中的初值。
  • lastprivate,主要是用来指定将线程中的私有变量的值在并行处理结束后 复制回主线程中的对应变量。 
  • reduction,用来指定一个或多个变量是私有的,并且在并行处理结束后 这些变量要执行指定的运算。 
  • nowait,忽略指定中暗含的等待 
  • num_threads,指定线程的个数 
  • schedule,指定如何调度for循环迭代 
  • shared,指定一个或多个变量为多个线程间的共享变量 
  • ordered,用来指定for循环的执行要按顺序执行 
  • copyprivate,用于single指导中的指定变量广播到并行区中其它线程 
  • copyin,用来指定一个threadprivate的变量的值要用主线程的值进行初始 化。 
  • default,用来指定并行处理区域内的变量的使用方式,缺省是shared

再写OpenMP的时候遇到的问题

1. OMP 的for 语句后面只可以选择一个clause。
2. 外部环境的export优先级低于程序里函数设置参数的优先级。
3. omp_set_num_threads 用于获取当前线程组(team)的线程数量,如果不在并行区调用,返回1.


下面是LU矩阵分解并行化的程序

#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <string.h>
#include <omp.h>

#define N 5
#define sytax "%6.3f " 
#define NUM_THREADS 4

float a[N][N];
float l[N][N];
float u[N][N];


void clumar(float a[N][N], float l[N][N], float u[N][N])
{
//	memset(l, 0, sizeof(l));
//	memset(u, 0, sizeof(u));
	int i, j, k;
	
	omp_set_num_threads(NUM_THREADS);
	
	#pragma omp parallel private(i, j, k) 
	{
		int id = omp_get_thread_num();
		printf("thread is %d\n", id);
		for(k = 1 +id ; k <= N; k += NUM_THREADS)
		{
			for(i = k+1; i <= N; ++i)
			{
				a[i][k] = a[i][k] / a[k][k];
			}
			
			for(i = k+1; i <= N; ++i)
			for(j = k+1; j <= N; ++j)
				a[i][j] = a[i][j] - a[i][k] * a[k][j];
		}
	}
	
	int chunk = 2;
	
	#pragma omp parallel for \
		shared(a, l, u, chunk) private(i, j) \
		schedule(dynamic, chunk) 
	for(i = 1; i <= N; ++i)
	{
		for(j = 1; j <= N; ++j)
		{
			if( j < i)
				l[i][j] = a[i][j];
			else
			u[i][j] = a[i][j];
		}
		l[i][i] = 1;
	}
}


void print(float data[N][N])
{
	int i, j; 
	for(i = 1; i <= N; ++i)
	{
		for(j = 1; j <= N; ++j)
		{
			printf(sytax, data[i][j]);
		}
		printf("\n");
	}
}
int main()
{
	
	
//	init_data(a, 10);     //为什么VS下面可以调用此函数而PGI的环境不支持,OpenMP 感觉各种奇葩 
	
	for(int i = 1; i <= N; ++i)
	{
		for(int j = 1; j <= N; ++j)
		{
			a[i][j] = i + j;
		}
	}
	
	clumar(a, l, u);
	
	printf("\n\nthe l Matrix value:\n\n");
	print(l);
	printf("\n\nthe u Matrix value:\n\n");
	print(u);
	
}



  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
1. 设计目的、意义(功能描述) 蒙特·卡罗方法(Monte Carlo method),也称统计模拟方法,是二十世纪四十年代中期由于科学技术的发展和电子计算机的发明,而被提出的一种以概率统计理论为指导的一类非常重要的数值计算方法。本次大作业主要是对蒙特·卡罗方法进行并行处理,通过OpenMP、MPI、.NET、Java、Win32API等一系列并行技术和并行机制对该算法进行并行处理,从而也进一步熟悉了蒙特·卡罗方法的串行算法和并行算法,实现了用蒙特·卡罗方法计算出半径为1单位的球体的体积,体会到了并行技术在实际生活中的应用。 2. 方案分析(解决方案) 蒙特·卡罗方法(Monte Carlo method)是指使用随机数(或更常见的伪随机数)来解决很多计算问题的方法。球的体积可以估算为:位于点模型内随机点个数与全体随机点个数的比值乘以包围盒的体积算的。 3. 设计分析 3.1 串行算法设计 假定球体用B表示,半径r=1单位,B1是包含B的参考立方体(在本例中是边长为2的正方体),在B1中产生N个均匀分布的伪随机点。对每个随机点检测其是否在B内,假设位于B内的随机点个数为N(in)(<=N),应用蒙特卡洛算法,则B的体积为 V=V1(N(in)/N) 其中V1是B1的体积。如果产生足够多的随机点,理论上可以获得任意逼近精度。 算法描述如下: BEGIN N=_MAX; FOR I=0;I<_MAX;I++ X=RANDOM(); Y=RANDOM(); Z=RANDOM(); IF (X*X+Y*Y+Z*Z)<=1 COUNT++; END IF; END FOR; BULK=V1*(COUNT/_MAX); END; 本算法主要是在参考立方体的选取上和定义的_MAX的值对结果影响较大,所以应该选择合适的数。 3.2 并行算法设计 对FOR循环进行划分使用两个处理器完成计算。例如对一个长为n的序列,首先划分得到两个长为n/2的序列,将其交给两个处理器分别处理;而后进一步划分得到四个长为n/4的序列,再分别交给四个处理器处理;如此递归下去最终得到结果。当然这是理想的划分情况,如果划分步骤不能达到平均分配的目的,那么结果的效率会相对较差。 伪代码如下: BEGIN N=_MAX; FOR1 I=0;I<_MAX/2;I++ X1=RANDOM(); Y1=RANDOM(); Z1=RANDOM(); IF (X1*X1+Y1*Y1+Z1*Z1)<=1 COUNT1++; END IF; END FOR1; FOR2 I=_MAX/2+1;I<_MAX;I++ X2=RANDOM(); Y2=RANDOM(); Z2=RANDOM(); IF (X2*X2+Y2*Y2+Z2*Z2)<=1 COUNT2++; END IF; END FOR2; BULK=V1*((COUNT1+ COUNT2)/_MAX); END; 3.3 理论加速比分析 实验中大量数据所产生的加速比比小量数据所产生的加速比要体现得更明显,并且数据生成的并行加速比随着处理器核的增加而增加。设处理器个数为p,数据量为n,由于正常情况下该快速排序算法的复杂度为O(nlogn),并行处理的时间复杂度为O(klogk),其中k=n/p,所以并行算法的时间复杂度为O((n/p)log(n/p)),理论加速比为nlogn/((n/p)log(n/p))=p+logp. 4. 功能模块实现与最终结果分析 4.1 基于OpenMP的并行算法实现 4.1.1 主要功能模块与实现方法 利用了OpenMP里面的#omp parallel sections将对两个for循环用两个线程并行化执行,以多线程方式并行运行程序,并行的算法步骤如下: (1)初始化_max = 10000000; (2)创建两个线程; (3)由OpenMP编译指导语句控制产生并行执行代码区段; (4)将数据存放到tianqing_count; (5)各线程调用算法得出结果; 并行算法的部分代码如下: #pragma omp parallel for private(tianqing_x,tianqing_y,tianqing_z) reduction(+:tianqing_count2) for (tianqing_i = 0; tianqing_i<tianqing_max; tianqing_i++) { tianqing_x = rand(); tianqing_x = tianqing_x / 32767; tianqing_y = rand(); tianqing_y = tianqing_y / 32767; tianqing_z = rand(); tianqing_z = tianqing_z / 32767; if ((tianqing_x*tianqing_x + tianqing_y*tianqing_y + tianqing_z*tianqing_z) work1.pSumto(b, 0, MAXN - 1)); Thread newthread1 = new Thread(thread1); 创建Work类的对象work2; ThreadStart thread2 = new ThreadStart(() => work2.pSumto(c, 0, MAXN - 1)); Thread newthread2 = new Thread(thread2); stopwatch.Start(); 启动线程1和线程2; 等待进程结束; stopwatch.Stop(); 得到结果; 4.5.2 实验加速比分析 实验中创建了两个线程,通过多次测试,得出实验结果:由上面的理论加速比分析可知,当线程数为2时,理论加速比为2+log2=3.但由于实际操作中硬件设备以及内存分配的影响,实验加速比达不到理论值3.实验加速比在2.6~2.7左右。 4.6 并行计算技术在实际系统中的应用 4.6.1 主要功能模块与实现方法 该飞机订票系统主要实现了对机票的一些基本信息进行存储和管理的功能。在系统中实现了对机票信息的增删改查,考虑到查询的方便性,对机票按照航班号进行排序,而此排序方法用并行快速排序运用进来。利用OpenMP的并行技术,对机票信息按顺序排列好,并分析了实验过程中的加速比。 4.6.2 实验加速比分析 实验中创建了两个线程,通过多次测试,得出实验结果:当数据量比较大时,加速比理论在1.9左右。数据量较大时体现出来的加速比更准确。由上面的理论加速比分析可知,当线程数为2时,理论加速比为2+log2=3.但由于实际操作中硬件设备以及内存分配的影响,实验加速比达不到理论值3.实验加速比在2.2~2.4左右。 5. 设计体会 虽然没有按时完成作业,但这份报告花了我好几天的时间,从开始的搭建并行计算平台到最后的程序运行成功可以说是对我的一个锻炼。每一次的遇到问题与每一次的解决问题都是一个成长。每一次遇到问题和解决问题都是一种锻炼,一种尝试,从我们上并行计算课我懂得了很多电脑硬件和软件的知识,这些可能对于我们这个专业以后都是没有机会接触的,所以我觉得选择了并行计算与多核多线程技术这门课是非常正确的。对OpenMP、MPI、WIN32API、Java、.NET的并行技术有了一定的了解。在搭建MPI并行程序这块,学习的知识尤为增加,这些都是在不断的摸索、学习中学会的。 这次的大作业虽然是对以前实验的整合,但它加深了我对并行计算的印象,也使我对并行计算知识的理解更加深刻,也使我认识到了自己很多不足之处。学习并行计算的历程不会因为完成本次大作业而停止,我们是为了用知识武装大脑而学习,通过学习充实自己的生活,要努力学习,争取以后能够完成规模更大的程序。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值