【OpenMP学习笔记】1:基本使用和critical指令

2023-12-09 14:48

本文主要是介绍【OpenMP学习笔记】1:基本使用和critical指令,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

MPI是可以针对分布式内存,在进程级别实现并行的API;OpenMP则是针对共享内存,在线程级别实现并行的API。

基本使用

不同于MPI的init和finalize,OpenMP用携带了parallel指令的预处理指令指示接下来的一个代码块被多个线程执行。

OpenMP预处理指令-(携带)->OpenMP指令-(携带)->OpenMP指令的子句。

隐式路障是OpenMP的一个特点,所有执行这个代码块的线程在同一个线程组中以隐式路障隐式同步。

#include<stdio.h>
#include<stdlib.h>//检查是否定义了_OPENMP预处理宏,即编译器是否支持OpenMP
#ifdef _OPENMP 
#include<omp.h> //支持时包含OpenMP头文件
#endifint main(int argc,char *argv[])
{//stdlib的strtol()函数把字符串转换成整形数//参数1:字符串首地址,跳过前面的空格符,遇到数字或正负符号才开始做转换//参数2:用于引用返回遇到非数字或'\0'结束转换时的字符指针所在地址//参数3:转换至几进制,取值2~36或0,取0时即默认为10进制int thrdCnt=strtol(argv[1],NULL,0);printf("strtol()函数从主函数参数解析得的线程数:%d\n",thrdCnt);
//# pragma omp指示后面接的是OpenMP的预处理指令//parallel指令表明之后的结构化代码块被多个线程执行//num_threads(线程数)子句指定执行后代码块的线程数
#   pragma omp parallel num_threads(thrdCnt){//如果不支持OpenMP,前面没有包含omp.h,则里面的函数也不可用//所以要在所有使用了omp.h的代码处做包含检查
#       ifdef _OPENMP//omp_get_thread_num()函数获得该线程的编号int myThrdNm=omp_get_thread_num();//omp_get_num_threads()函数获得总的线程数int allNmThrds=omp_get_num_threads();
#       else//当不能使用OpenMP时,只有一个线程,线程号是0int myThrdNm=0;//当不能使用OpenMP时,只有一个线程,线程数目是1int allNmThrds=1;
#       endif//为了验证"隐式路障",此处sleep()不同的时间,不妨按线程编号延时sleep(myThrdNm*3);//C语言里sleep()的单位是秒printf("我是%d/%d\n",myThrdNm,allNmThrds);}//隐式路障:完成代码块的线程要等待其它所有线程完成此代码块printf("路障解除了\n");return 0;
}

输出

[lzh@hostlzh OpenMP]$ !gcc
gcc -fopenmp -o hello.o hello.c
[lzh@hostlzh OpenMP]$ ./hello.o 4
strtol()函数从主函数参数解析得的线程数:4
我是0/4
我是1/4
我是2/4
我是3/4
路障解除了
[lzh@hostlzh OpenMP]$

critical指令

OpenMP里变量的作用域可以按照块内是否共享分为共享作用域私有作用域。对于并行代码块而言,在块前声明的变量缺省作用域是共享的(不过这个”共享”当然不能穿透函数)。

某些地方未使用critical时可能存在的问题

当块内共同操作了共享的资源时,不对其做互斥保护就可能会在运行时出问题。因为只能保证一次汇编级的指令是原子的,甚至不能保证一条C语言语句在并发执行过程中不会发生线程的切换,在并行的情况下就更加危险了:

#include<stdio.h>
#include<stdlib.h>
#include<omp.h>int main(int argc,char *argv[])
{int a=20;int thrdCnt=strtol(argv[1],NULL,10);
#   pragma omp parallel num_threads(thrdCnt)    a=a-1;//并行块中访问了共享变量aprintf("a=%d\n",a);//最终输出看一下return 0;
}

输出

[lzh@hostlzh OpenMP]$ !gcc
gcc -fopenmp -o test1.o test1.c
[lzh@hostlzh OpenMP]$ ./test1.o 15
a=5
[lzh@hostlzh OpenMP]$ ./test1.o 15
a=5
[lzh@hostlzh OpenMP]$ ./test1.o 15
a=5
[lzh@hostlzh OpenMP]$ ./test1.o 15
a=5
[lzh@hostlzh OpenMP]$ ./test1.o 15
a=5
[lzh@hostlzh OpenMP]$ ./test1.o 15
a=6
[lzh@hostlzh OpenMP]$ ./test1.o 15
a=5
[lzh@hostlzh OpenMP]$ ./test1.o 15
a=5

才执行了这么几次就发生了出错,可见问题严重。

使用critical时
#include<stdio.h>
#include<stdlib.h>
#include<omp.h>int main(int argc,char *argv[])
{int a=20;int b=20;int thrdCnt=strtol(argv[1],NULL,10);
#   pragma omp parallel num_threads(thrdCnt){//OpenMP指令critical安排线程对接下来的代码块互斥访问
#       pragma omp criticala=a-1;//共享变量a受critical保护互斥访问b=b-1;//共享变量b未受critical保护}printf("a=%d\nb=%d\n",a,b);//最终输出看一下return 0;
}

输出

[lzh@hostlzh OpenMP]$ !gcc
gcc -fopenmp -o test1.o test1.c
[lzh@hostlzh OpenMP]$ ./test1.o 15
a=5
b=5
[lzh@hostlzh OpenMP]$ ./test1.o 15
a=5
b=5
[lzh@hostlzh OpenMP]$ ./test1.o 15
a=5
b=5
[lzh@hostlzh OpenMP]$ ./test1.o 15
a=5
b=5
[lzh@hostlzh OpenMP]$ ./test1.o 15
a=5
b=5
[lzh@hostlzh OpenMP]$ ./test1.o 15
a=5
b=5
[lzh@hostlzh OpenMP]$ ./test1.o 15
a=5
b=5
[lzh@hostlzh OpenMP]$ ./test1.o 15
a=5
b=5
[lzh@hostlzh OpenMP]$ ./test1.o 15
a=5
b=5
[lzh@hostlzh OpenMP]$ ./test1.o 15
a=5
b=5
[lzh@hostlzh OpenMP]$ ./test1.o 15
a=5
b=5
[lzh@hostlzh OpenMP]$ ./test1.o 15
a=5
b=5
[lzh@hostlzh OpenMP]$ ./test1.o 15
a=5
b=5
[lzh@hostlzh OpenMP]$ ./test1.o 15
a=5
b=6
[lzh@hostlzh OpenMP]$ ./test1.o 15
a=5
b=5
[lzh@hostlzh OpenMP]$ ./test1.o 15
a=5
b=5
[lzh@hostlzh OpenMP]$ ./test1.o 15
a=5
b=5
[lzh@hostlzh OpenMP]$ 

可见受critical指令保护的a能够正常执行了,而不受保护的b仍然会发生前面的问题。

这篇关于【OpenMP学习笔记】1:基本使用和critical指令的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/474087

相关文章

使用Python和Pyecharts创建交互式地图

《使用Python和Pyecharts创建交互式地图》在数据可视化领域,创建交互式地图是一种强大的方式,可以使受众能够以引人入胜且信息丰富的方式探索地理数据,下面我们看看如何使用Python和Pyec... 目录简介Pyecharts 简介创建上海地图代码说明运行结果总结简介在数据可视化领域,创建交互式地

Java Stream流使用案例深入详解

《JavaStream流使用案例深入详解》:本文主要介绍JavaStream流使用案例详解,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友参考下吧... 目录前言1. Lambda1.1 语法1.2 没参数只有一条语句或者多条语句1.3 一个参数只有一条语句或者多

Java Spring 中 @PostConstruct 注解使用原理及常见场景

《JavaSpring中@PostConstruct注解使用原理及常见场景》在JavaSpring中,@PostConstruct注解是一个非常实用的功能,它允许开发者在Spring容器完全初... 目录一、@PostConstruct 注解概述二、@PostConstruct 注解的基本使用2.1 基本代

C#使用StackExchange.Redis实现分布式锁的两种方式介绍

《C#使用StackExchange.Redis实现分布式锁的两种方式介绍》分布式锁在集群的架构中发挥着重要的作用,:本文主要介绍C#使用StackExchange.Redis实现分布式锁的... 目录自定义分布式锁获取锁释放锁自动续期StackExchange.Redis分布式锁获取锁释放锁自动续期分布式

springboot使用Scheduling实现动态增删启停定时任务教程

《springboot使用Scheduling实现动态增删启停定时任务教程》:本文主要介绍springboot使用Scheduling实现动态增删启停定时任务教程,具有很好的参考价值,希望对大家有... 目录1、配置定时任务需要的线程池2、创建ScheduledFuture的包装类3、注册定时任务,增加、删

使用Python实现矢量路径的压缩、解压与可视化

《使用Python实现矢量路径的压缩、解压与可视化》在图形设计和Web开发中,矢量路径数据的高效存储与传输至关重要,本文将通过一个Python示例,展示如何将复杂的矢量路径命令序列压缩为JSON格式,... 目录引言核心功能概述1. 路径命令解析2. 路径数据压缩3. 路径数据解压4. 可视化代码实现详解1

Pandas透视表(Pivot Table)的具体使用

《Pandas透视表(PivotTable)的具体使用》透视表用于在数据分析和处理过程中进行数据重塑和汇总,本文就来介绍一下Pandas透视表(PivotTable)的具体使用,感兴趣的可以了解一下... 目录前言什么是透视表?使用步骤1. 引入必要的库2. 读取数据3. 创建透视表4. 查看透视表总结前言

Python 交互式可视化的利器Bokeh的使用

《Python交互式可视化的利器Bokeh的使用》Bokeh是一个专注于Web端交互式数据可视化的Python库,本文主要介绍了Python交互式可视化的利器Bokeh的使用,具有一定的参考价值,感... 目录1. Bokeh 简介1.1 为什么选择 Bokeh1.2 安装与环境配置2. Bokeh 基础2

Android使用ImageView.ScaleType实现图片的缩放与裁剪功能

《Android使用ImageView.ScaleType实现图片的缩放与裁剪功能》ImageView是最常用的控件之一,它用于展示各种类型的图片,为了能够根据需求调整图片的显示效果,Android提... 目录什么是 ImageView.ScaleType?FIT_XYFIT_STARTFIT_CENTE

Java学习手册之Filter和Listener使用方法

《Java学习手册之Filter和Listener使用方法》:本文主要介绍Java学习手册之Filter和Listener使用方法的相关资料,Filter是一种拦截器,可以在请求到达Servl... 目录一、Filter(过滤器)1. Filter 的工作原理2. Filter 的配置与使用二、Listen