`
lovnet
  • 浏览: 6879158 次
  • 性别: Icon_minigender_1
  • 来自: 武汉
文章分类
社区版块
存档分类
最新评论

OpenMP并行程序设计(二)

阅读更多
OpenMP并行程序设计(二)
1、fork/join并行执行模式的概念
OpenMP是一个编译器指令和库函数的集合,主要是为共享式存储计算机上的并行程序设计使用的。
前面一篇文章中已经试用了OpenMP的一个Parallel for指令。从上篇文章中我们也可以发现OpenMP并行执行的程序要全部结束后才能执行后面的非并行部分的代码。这就是标准的并行模式fork/join式并行模式,共享存储式并行程序就是使用fork/join式并行的。
标准并行模式执行代码的基本思想是,程序开始时只有一个主线程,程序中的串行部分都由主线程执行,并行的部分是通过派生其他线程来执行,但是如果并行部分没有结束时是不会执行串行部分的,如上一篇文章中的以下代码:
int main(int argc, char* argv[])
{
clock_t t1 = clock();
#pragma omp parallel for
for ( int j = 0; j < 2; j++ ){
test();
}
clock_t t2 = clock();
printf("Total time = %d\n", t2-t1);
test();
return 0;
}
在没有执行完for循环中的代码之前,后面的clock_t t2 = clock();这行代码是不会执行的,如果和调用线程创建函数相比,它相当于先创建线程,并等待线程执行完,所以这种并行模式中在主线程里创建的线程并没有和主线程并行运行。
2、OpenMP指令和库函数介绍
下面来介绍OpenMP的基本指令和常用指令的用法,
在C/C++中,OpenMP指令使用的格式为
pragma omp 指令 [子句[子句]…]
前面提到的parallel for就是一条指令,有些书中也将OpenMP的“指令”叫做“编译指导语句”,后面的子句是可选的。例如:
#pragma omp parallel private(i, j)
parallel 就是指令, private是子句
为叙述方便把包含#pragma和OpenMP指令的一行叫做语句,如上面那行叫parallel语句。
OpenMP的指令有以下一些:
parallel,用在一个代码段之前,表示这段代码将被多个线程并行执行
for,用于for循环之前,将循环分配到多个线程中并行执行,必须保证每次循环之间无相关性。
parallel for, parallel 和 for语句的结合,也是用在一个for循环之前,表示for循环的代码将被多个线程并行执行。
sections,用在可能会被并行执行的代码段之前
parallel sections,parallel和sections两个语句的结合
critical,用在一段代码临界区之前
single,用在一段只被单个线程执行的代码段之前,表示后面的代码段将被单线程执行。
flush
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函数的配对操作函数,关闭一个锁
OpenMP的子句有以下一些
private, 指定每个线程都有它自己的变量私有副本。
firstprivate指定每个线程都有它自己的变量私有副本,并且变量要被继承主线程中的初值。
lastprivate主要是用来指定将线程中的私有变量的值在并行处理结束后复制回主线程中的对应变量。
reduce用来指定一个或多个变量是私有的,并且在并行处理结束后这些变量要执行指定的运算。
nowait忽略指定中暗含的等待
num_threads指定线程的个数
schedule指定如何调度for循环迭代
shared指定一个或多个变量为多个线程间的共享变量
ordered用来指定for循环的执行要按顺序执行
copyprivate用于single指令中的指定变量为多个线程的共享变量
copyin用来指定一个threadprivate的变量的值要用主线程的值进行初始化。
default用来指定并行处理区域内的变量的使用方式,缺省是shared
3、parallel 指令的用法
parallel 是用来构造一个并行块的,也可以使用其他指令如for、sections等和它配合使用。
在C/C++中,parallel的使用方法如下:
#pragma omp parallel [for | sections] [子句[子句]…]
{
//代码
}
parallel语句后面要跟一个大括号对将要并行执行的代码括起来。
void main(int argc, char *argv[]) {
#pragma omp parallel
{
printf(“Hello, World!\n”);
}
}
执行以上代码将会打印出以下结果
Hello, World!
Hello, World!
Hello, World!
Hello, World!
可以看得出parallel语句中的代码被执行了四次,说明总共创建了4个线程去执行parallel语句中的代码。
也可以指定使用多少个线程来执行,需要使用num_threads子句:
void main(int argc, char *argv[]) {
#pragma omp parallel num_threads(8)
{
printf(“Hello, World!, ThreadId=%d\n”, omp_get_thread_num() );
}
}
执行以上代码,将会打印出以下结果:
Hello, World!, ThreadId = 2
Hello, World!, ThreadId = 6
Hello, World!, ThreadId = 4
Hello, World!, ThreadId = 0
Hello, World!, ThreadId = 5
Hello, World!, ThreadId = 7
Hello, World!, ThreadId = 1
Hello, World!, ThreadId = 3
从ThreadId的不同可以看出创建了8个线程来执行以上代码。所以parallel指令是用来为一段代码创建多个线程来执行它的。parallel块中的每行代码都被多个线程重复执行。
和传统的创建线程函数比起来,相当于为一个线程入口函数重复调用创建线程函数来创建线程并等待线程执行完。
4、for指令的使用方法
for指令则是用来将一个for循环分配到多个线程中执行。for指令一般可以和parallel指令合起来形成parallel for指令使用,也可以单独用在parallel语句的并行块中。
#pragma omp [parallel] for [子句]
for循环语句
先看看单独使用for语句时是什么效果:
int j = 0;
#pragma omp for
for ( j = 0; j < 4; j++ ){
printf(j = %d, ThreadId = %d\n, j, omp_get_thread_num());
}
执行以上代码后打印出以下结果
j = 0, ThreadId = 0
j = 1, ThreadId = 0
j = 2, ThreadId = 0
j = 3, ThreadId = 0
从结果可以看出四次循环都在一个线程里执行,可见for指令要和parallel指令结合起来使用才有效果:
如以下代码就是parallel 和for一起结合成parallel for的形式使用的:
int j = 0;
#pragma omp parallel for
for ( j = 0; j < 4; j++ ){
printf(j = %d, ThreadId = %d\n, j, omp_get_thread_num());
}
执行后会打印出以下结果:
j = 0, ThreadId = 0
j = 2, ThreadId = 2
j = 1, ThreadId = 1
j = 3, ThreadId = 3
可见循环被分配到四个不同的线程中执行。
上面这段代码也可以改写成以下形式:
int j = 0;
#pragma omp parallel
{
#pragma omp for
for ( j = 0; j < 4; j++ ){
printf(j = %d, ThreadId = %d\n, j, omp_get_thread_num());
}
}
执行以上代码会打印出以下结果:
j = 1, ThreadId = 1
j = 3, ThreadId = 3
j = 2, ThreadId = 2
j = 0, ThreadId = 0
在一个parallel 块中也可以有多个for语句,如:
int j;
#pragma omp parallel
{
#pragma omp for
for ( j = 0; j < 100; j++ ){
}
#pragma omp for
for ( j = 0; j < 100; j++ ){
}
}
for 循环语句中,书写是需要按照一定规范来写才可以的,即for循环小括号内的语句要按照一定的规范进行书写,for语句小括号里共有三条语句
for( i=start; i < end; i++)
i=start; 是for循环里的第一条语句,必须写成 “变量=初值” 的方式。如 i=0
i < end;是for循环里的第二条语句,这个语句里可以写成以下4种形式之一:
变量 < 边界值
变量 <= 边界值
变量 > 边界值
变量 >= 边界值
如 i>10i< 10 i>=10i>10 等等
最后一条语句i++可以有以下9种写法之一
i++
++i
i--
--i
i += inc
i -= inc
i = i + inc
i = inc + i
i = i –inc
例如i += 2;i -= 2;i = i + 2;i = i - 2;都是符合规范的写法。
5 sections和section指令的用法
section语句是用在sections语句里用来将sections语句里的代码划分成几个不同的段,每段都并行执行。用法如下:
#pragma omp [parallel] sections [子句]
{
#pragma omp section
{
代码块
}
}
先看一下以下的例子代码:
void main(int argc, char *argv)
{
#pragma omp parallel sections {
#pragma omp section
printf(“section 1 ThreadId = %d\n”, omp_get_thread_num());
#pragma omp section
printf(“section 2 ThreadId = %d\n”, omp_get_thread_num());
#pragma omp section
printf(“section 3 ThreadId = %d\n”, omp_get_thread_num());
#pragma omp section
printf(“section 4 ThreadId = %d\n”, omp_get_thread_num());
}
执行后将打印出以下结果:
section 1 ThreadId = 0
section 2 ThreadId = 2
section 4 ThreadId = 3
section 3 ThreadId = 1
从结果中可以发现第4段代码执行比第3段代码早,说明各个section里的代码都是并行执行的,并且各个section被分配到不同的线程执行。
使用section语句时,需要注意的是这种方式需要保证各个section里的代码执行时间相差不大,否则某个section执行时间比其他section过长就达不到并行执行的效果了。
上面的代码也可以改写成以下形式:
void main(int argc, char *argv)
{
#pragma omp parallel {
#pragma omp sections
{
#pragma omp section
printf(“section 1 ThreadId = %d\n”, omp_get_thread_num());
#pragma omp section
printf(“section 2 ThreadId = %d\n”, omp_get_thread_num());
}
#pragma omp sections
{
#pragma omp section
printf(“section 3 ThreadId = %d\n”, omp_get_thread_num());
#pragma omp section
printf(“section 4 ThreadId = %d\n”, omp_get_thread_num());
}
}
执行后将打印出以下结果:
section 1 ThreadId = 0
section 2 ThreadId = 3
section 3 ThreadId = 3
section 4 ThreadId = 1
这种方式和前面那种方式的区别是,两个sections语句是串行执行的,即第二个sections语句里的代码要等第一个sections语句里的代码执行完后才能执行。
用for语句来分摊是由系统自动进行,只要每次循环间没有时间上的差距,那么分摊是很均匀的,使用section来划分线程是一种手工划分线程的方式,最终并行性的好坏得依赖于程序员。
本篇文章中讲的几个OpenMP指令parallel, for, sections, section实际上都是用来如何创建线程的,这种创建线程的方式比起传统调用创建线程函数创建线程要更方便,并且更高效。
当然,创建线程后,线程里的变量是共享的还是其他方式,主线程中定义的变量到了并行块内后还是和传统创建线程那种方式一样的吗?创建的线程是如何调度的?等等诸如此类的问题到下一篇文章中进行讲解。
分享到:
评论

相关推荐

    MPI与OpenMP并行程序设计(C语言版)美国教授写的

    《MPI与OpenMP并行程序设计(C语言版)》是美国Oregon州立大学的Michael J.Quinn教授在多年讲授“并行程序设计”课程的基础上编写而成的,主要介绍用C语言,并结合使用MPI和OpenMP进行并行程序设计,内容包括并行体系...

    MPI与OpenMP并行程序设计:C语言版,mpi和openmp混合编程,C,C++

    在“MPI与OpenMP并行程序设计:C语言版”这本书中,读者可以深入学习如何结合这两种技术,创建高效的并行程序。内容可能包括如何设置并行环境、使用MPI进行进程间通信、OpenMP的并行化策略、混合编程的实践示例以及...

    MPI与OpenMP并行程序设计:C语言版.pdf

    《MPI与OpenMP并行程序设计:C语言版》是一本介绍如何使用C语言进行并行程序设计的教材。在当今多核处理器和并行计算日益普及的背景下,掌握并行程序设计成为了计算机及相关领域专业人士的重要技能。本书主要围绕MPI...

    MPI与OpenMP并行程序设计pdf

    MPI与OpenMP并行程序设计中文电子书,讲得很不错

    mpi与openmp并行程序设计ppt

    这些PPT为学习和理解MPI和OpenMP提供了一个良好的起点,涵盖了并行程序设计的基础知识,同时也展示了如何将这些知识应用于实际问题中。通过深入研究这些材料,开发者能够掌握并行计算的基本原理,从而在高性能计算...

    MPI与OpenMP并行程序设计

    《MPI与OpenMP并行程序设计》是一本深入探讨并行计算领域中两种主流技术——Message Passing Interface(MPI)和OpenMP的书籍。并行计算是解决大规模计算问题的关键技术,尤其是在高性能计算、数据分析和机器学习等...

    OpenMP并行程序设计

    OpenMP(Open Multi-Processing)是一种用于编写多线程并行程序的API,主要应用于共享内存的多处理器系统。它的核心特点在于通过编译器指令、运行时库和环境变量来实现并行化,允许程序员在不牺牲可移植性的前提下,...

    MPI与OpenMP并行程序设计:C语言版

    ### MPI与OpenMP并行程序设计:C语言版 #### MPI与OpenMP简介 在现代高性能计算领域,利用多核处理器或分布式系统进行并行计算是提高计算效率的关键技术之一。其中,MPI(Message Passing Interface)和OpenMP是两...

    MPI与OpenMP并行计算的实验报告及源程序

    "MPI实验报告.doc"很可能是对使用MPI进行并行计算的实验过程、结果和分析的详细记录,可能涵盖了如何设置MPI环境、编写并行程序、运行并行程序以及性能评估等内容。实验可能涉及矩阵乘法、求解线性方程组等典型问题...

    openmp并行程序设计教程

    ### OpenMP并行程序设计教程知识点详解 #### 一、OpenMP简介 ##### 1.1 什么是OpenMP? OpenMP是一种应用编程接口(API),主要用于显式地指导多线程共享内存并行计算。它由三个主要部分组成: - **编译器指令**...

    基于OpenMP的并行程序设计

    随着计算机技术的发展,多核处理器已经成为了主流,对于开发者来说,掌握OpenMP并行程序设计是提高程序性能和开发效率的有效手段。许多学术论文和研究成果都表明了OpenMP在多核并行程序设计中的有效性。例如,上述...

    OpenMP 并行算法设计

    在设计OpenMP并行算法时,我们需要考虑以下几个关键知识点: 1. **并行区域(Parallel Regions)**:OpenMP并行编程的基础是`#pragma omp parallel`指令,它定义了一个并行区域,编译器会将这个区域内的代码转换为...

    MPI与OpenMP并行程序设

    《MPI与OpenMP并行程序设计:C语言版》是一本深入浅出的并行计算入门书籍,专注于介绍两种主流的并行编程模型——Message Passing Interface(MPI)和Open Multi-Processing(OpenMP)。这两者在现代高性能计算领域...

    OpenMP并行计算程序设计基础

    ### OpenMP并行计算程序设计基础 #### 一、一个简单的OpenMP例子 在这个部分,作者通过一个具体的示例展示了如何使用OpenMP实现一个简单的并行程序。该例子使用了C++语言,并通过Visual Studio 2010进行了实现。 ...

    并行程序设计导论课后答案_2.7z

    并行程序设计是计算机科学中的一个重要领域,它涉及到如何利用多处理器或多核心系统来同时执行多个任务或同一任务的不同部分,以提高计算效率和性能。本主题主要关注并行编程的基础概念、方法和技术,以及与C语言...

    MPI与OpenMP并行程序设计:C语言版,mpi和openmp混合编程,C,C++源码.zip

    《MPI与OpenMP并行程序设计:C语言版,mpi和openmp混合编程,C,C++源码》这个资源是关于并行计算领域的,主要聚焦在MPI(Message Passing Interface)和OpenMP两种并行编程模型的结合使用,尤其针对C语言进行讲解。...

    实现(串行,openmp、mpi、openmp+mpi)快速排序算法,并作出时间对比图

    (1)使用MPI、OpenMP、MPI+OpenMP编写上述并行程序。 (2)使用VTune等工具对程序进行瓶颈分析和优化。 (3)提交程序源代码、变量和语句的详细说明。 (4)在实验报告中通过图表说明CPU串行程序和三种并行程序在...

    并行程序设计导论课后答案(英文版含代码)

    并行程序设计是计算机科学中的一个重要领域,它涉及到如何利用多核处理器或分布式系统来同时执行多个任务,以提高计算效率。"并行程序设计导论"这门课程旨在教授学生如何有效地设计、实现和优化并行程序。课后答案...

Global site tag (gtag.js) - Google Analytics