Openmp Runtime 库函数汇总(上)
Openmp Runtime 库函数汇总(上)
- omp_in_parallel,如果当前线程正在并行域内部,则此函数返回true,否则返回false。
#include <stdio.h>
#include <omp.h>
int main()
{
printf("0> Not In parallel region value = %d\n",
omp_in_parallel());
// 在这里函数返回的 false 在 C 语言当中返回值等于 int 类型的 0
if (omp_in_parallel())
{
printf("1> In parallel region value = %d\n",
omp_in_parallel());
}
#pragma omp parallel num_threads(2) default(none)
{
// 这里函数的返回值是 1 在 C 语言当中对应 int 类型的 1
if (omp_in_parallel())
{
printf("2> In parallel region value = %d\n",
omp_in_parallel());
}
}
return 0;
}
上面的程序的输出结果如下所示:
0> Not In parallel region value = 0
2> In parallel region value = 1
2> In parallel region value = 1
需要注意的是在上面的函数 omp_in_parallel 使用时需要注意,如果你的并行域只有一个线程的时候 omp_in_parallel 返回的是 false。比如下面的例子:
#include <stdio.h>
#include <omp.h>
int main()
{
printf("0> Not In parallel region value = %d\n",
omp_in_parallel());
// 在这里函数返回的 false 在 C 语言当中返回值等于 int 类型的 0
if (omp_in_parallel())
{
printf("1> In parallel region value = %d\n",
omp_in_parallel());
}
// 只有一个线程,因此并不会激活并行域
#pragma omp parallel num_threads(1) default(none)
{
// 这里函数的返回值是 1 在 C 语言当中对应 int 类型的 1
if (omp_in_parallel())
{
printf("2> In parallel region value = %d\n",
omp_in_parallel());
}
}
return 0;
}
在上面的程序当中,因为并行域当中只有一个线程,因此不会激活,所以即使在 parallel 代码块内不,这个 omp_in_parallel 也不会被触发,上面的程序只会输出第一个 printf 的内容:
0> Not In parallel region value = 0
- omp_get_thread_num,这个函数的主要作用是用于返回当前并行域的线程组当中的唯一 ID,在一个串行代码当中,这个函数的返回结果之中等于 0 ,在并行域当中这个函数的返回值的区间等于 [0, num_threads - 1],如果是一个线程组的 master 线程调用这个函数,这个函数的返回值始终是 0,对应的测试代码如下所示:
#include <stdio.h>
#include <omp.h>
int main()
{
printf("Non parallel region: omp_get_thread_num() = %d\n", omp_get_thread_num());
#pragma omp parallel num_threads(5) default(none)
{
printf("In parallel region: omp_get_thread_num() = %d\n", omp_get_thread_num());
#pragma omp master
{
printf("In parallel region master: omp_get_thread_num() = %d\n", omp_get_thread_num());
}
}
return 0;
}
上面的程序的输出结果如下所示:
Non parallel region: omp_get_thread_num() = 0
In parallel region: omp_get_thread_num() = 0
In parallel region master: omp_get_thread_num() = 0
In parallel region: omp_get_thread_num() = 4
In parallel region: omp_get_thread_num() = 1
In parallel region: omp_get_thread_num() = 2
In parallel region: omp_get_thread_num() = 3
在上面的代码当中我们可以看到,在非并行域当中(第一个 printf) 函数的输出结果是 0,在并行域当中程序的输出结果范围是 [0. num_threads],如果一个线程是 master 线程的话,那么它对应的线程组当中的返回值就是0。
- omp_get_team_size,这个函数的主要作用就是返回一个线程组当中的线程个数。这个函数接受一个参数,他的函数原型为
int omp_get_team_size(int level);,这个参数的 level 的含义就是并行域的嵌套层级,这个参数的范围是 [0, omp_get_level],如果传入的参数不在这个范围,那么这个函数的返回值为 -1,如果你在一个并行域传入的 level 的参数是 omp_get_level ,那么这个函数的返回值和 omp_get_num_threads 的返回值相等。
#include <stdio.h>
#include <omp.h>
int main()
{
omp_set_nested(1);
int level = omp_get_level();
int size = omp_get_team_size(level);
printf("Non parallel region : level = %d size = %d\n", level, size);
#pragma omp parallel num_threads(5) default(none)
{
int level = omp_get_level();
int size = omp_get_team_size(level);
printf("level = %d size = %d\n", level, size);
#pragma omp parallel num_threads(2) default(none)
{
int level = omp_get_level();
int size = omp_get_team_size(level);
printf("level = %d size = %d\n", level, size);
printf("Up one level team size = %d\n", omp_get_team_size(level - 1));
}
}
return 0;
}
上面的程序的输出结果如下所示:
Non parallel region : level = 0 size = 1
level = 1 size = 5
level = 1 size = 5
level = 1 size = 5
level = 1 size = 5
level = 1 size = 5
level = 2 size = 2
Up one level team size = 5
level = 2 size = 2
Up one level team size = 5
level = 2 size = 2
Up one level team size = 5
level = 2 size = 2
level = 2 size = 2
Up one level team size = 5
level = 2 size = 2
Up one level team size = 5
level = 2 size = 2
Up one level team size = 5
Up one level team size = 5
level = 2 size = 2
Up one level team size = 5
level = 2 size = 2
Up one level team size = 5
level = 2 size = 2
Up one level team size = 5
在上面的代码当中在非并行域的代码当中,程序的输出结果和我们上面谈到的是相同的,level 等于 0,team size 等于 1,在并行域当中输出的结果也是符合预期的,我们来看一下最后两个输出,倒数第一个输出是查看上一个 level 的输出结果,可以看到他的输出结果等于 5,这和我们设置的 5 个线程是相符的。
- omp_get_num_procs,这个函数相对比较简单,主要是返回你的系统当中处理器的数量。
#include <stdio.h>
#include <omp.h>
int main()
{
int nprocs = omp_get_num_procs();
printf("Number of processors = %d\n", nprocs);
return 0;
}
- omp_in_final,这个函数主要是查看当前线程是否在最终任务或者包含任务当中,比如在下面的例子当中,我们就可以测试这个函数:
#include <stdio.h>
#include <omp.h>
int echo(int n)
{
int ret;
#pragma omp task shared(ret, n) final(n <= 10)
{
if(omp_in_final())
{
printf("In final n = %d\n", n);
ret = n;
}
else
{
ret = 1 + echo(n - 1);
}
}
return ret;
}
int main()
{
printf("echo(100) = %d\n", echo(100));
return 0;
}
上面的程序的输出结果如下所示:
In final n = 10
echo(100) = 100
在上面的程序我们在函数 echo 当中定义了一个任务,当参数 n <= 10 的时候,这个任务会变成一个 final 任务,因此在 n == 10 的时候,这个函数的 omp_in_final 会返回 true,因此会直接将 10 赋值给 ret ,不会进行递归调用,因此我们得到了上面的输出结果。
- omp_get_nested ,这个函数是用于判断是否开启并行区域的嵌套,如果开启了并行区域的嵌套,那么这个函数就返回 true ,否则就返回 false ,对应 C 语言的值分别为 1 和 0。在 OpenMP 当中默认是关闭的,你可以使用函数 omp_set_nested(1) 进行开启,或者使用 omp_set_nested(0) 关闭并行区域的嵌套。你可以对并行区域的嵌套有所疑惑,我们来看下面两个例子,你就豁然开朗了。
#include <stdio.h>
#include <omp.h>
int main()
{
// omp_set_nested(1);
#pragma omp parallel num_threads(2) default(none)
{
printf("Outer tid = %d level = %d num_threads = %d\n",
omp_get_thread_num(), omp_get_active_level(),
omp_get_num_threads());
#pragma omp parallel num_threads(2) default(none)
{
printf("Inner tid = %d level = %d num_threads = %d\n",
omp_get_thread_num(), omp_get_active_level(),
omp_get_num_threads());
}
}
return 0;
}
上面的程序的输出结果如下所示:
Outer tid = 0 level = 1 num_threads = 2
Inner tid = 0 level = 1 num_threads = 1
Outer tid = 1 level = 1 num_threads = 2
Inner tid = 0 level = 1 num_threads = 1
我们再来看一下如果我们开启了并行区域的嵌套之后程序的输出结果:
#include <stdio.h>
#include <omp.h>
int main()
{
omp_set_nested(1);
#pragma omp parallel num_threads(2) default(none)
{
printf("Outer tid = %d level = %d num_threads = %d\n",
omp_get_thread_num(), omp_get_active_level(),
omp_get_num_threads());
#pragma omp parallel num_threads(2) default(none)
{
printf("Inner tid = %d level = %d num_threads = %d\n",
omp_get_thread_num(), omp_get_active_level(),
omp_get_num_threads());
}
}
return 0;
}
上面的程序的输出结果如下所示:
Outer tid = 0 level = 1 num_threads = 2
Outer tid = 1 level = 1 num_threads = 2
Inner tid = 0 level = 2 num_threads = 2
Inner tid = 1 level = 2 num_threads = 2
Inner tid = 0 level = 2 num_threads = 2
Inner tid = 1 level = 2 num_threads = 2
我们可以对比一下两个程序的输出结果的差异,我们可以看到当我们允许并行嵌套之后,程序的输出结果会更多一点,这是因为如果我们没有开启的话,子并行域每个线程只会启动一个线程,如果我们开启的话,那么每个线程就会重新启动 num_threads 个线程,比如在上面两个代码当中,对于第一份代码外部并行块会启动两个线程,然后在每个线程的内部有一个并行块,但是因为没有启动,因此不管你的 num_threads 设置成多少,每个线程只会启动一个线程,因此最终会有 4 个 printf 语句输出。而对于第二份代码,是启动了嵌套代码的,外部并行块有两个线程,在内部因为是开启了,这两个线程会分别创建 num_threads 个内部线程去执行内部代码块,因此会有 2 个外部线程 4 (2x2)个内部线程,一共会有 6 个输出,因此就符合上面的结果了。其实不仅可以嵌套两层,还可以嵌套更多层,原理也是一样的分析方法。
omp_get_active_level,这个函数主要是返回当前线程所在的并行域的嵌套的并行块的级别,从 1 开始,从外往内没加一层这个值就加一,如果没有启动并行嵌套,那么这个函数的返回值就是 1。
omp_set_max_active_levels,我们在上面提到了,我们可以不断的进行并行域的嵌套,我们可以使用这个函数进行设置最大的嵌套的层数,如果超过这个层数那么就与不启动嵌套的效果一样了,也就是说 num_threads 不会发生效果了。
我们现在设置允许设置的最大的并行块的嵌套层数等于 2,但是我们一共有三个嵌套块,我们可以看一下对第三层嵌套的代码的影响。
#include <stdio.h>
#include <omp.h>
int main()
{
omp_set_nested(1);
omp_set_max_active_levels(2);
#pragma omp parallel num_threads(2) default(none)
{
printf("1> omp_get_level = %d omp_get_active_level = %d\n", omp_get_level(), omp_get_active_level());
#pragma omp parallel num_threads(2) default(none)
{
printf("2> omp_get_level = %d omp_get_active_level = %d\n", omp_get_level(), omp_get_active_level());
#pragma omp parallel num_threads(2) default(none)
{
printf("3> omp_get_level = %d omp_get_active_level = %d\n", omp_get_level(), omp_get_active_level());
}
}
}
return 0;
}
上面的程序的输出结果如下所示(3> 一共输出了 4 次,因为它的外部线程的个数是 4 (2x2)):
1> omp_get_level = 1 omp_get_active_level = 1
1> omp_get_level = 1 omp_get_active_level = 1
2> omp_get_level = 2 omp_get_active_level = 2
3> omp_get_level = 3 omp_get_active_level = 2
2> omp_get_level = 2 omp_get_active_level = 2
2> omp_get_level = 2 omp_get_active_level = 2
3> omp_get_level = 3 omp_get_active_level = 2
2> omp_get_level = 2 omp_get_active_level = 2
3> omp_get_level = 3 omp_get_active_level = 2
3> omp_get_level = 3 omp_get_active_level = 2
我们现在将函数 omp_set_max_active_levels 的参数设置成 3,也就是说允许的最大的并行块的嵌套层数等于3,重新看一下程序的输出结果是什么(将 omp_set_max_active_levels(2) 改成 omp_set_max_active_levels(3))之后,程序的输出结果如下所示:
1> omp_get_level = 1 omp_get_active_level = 1
1> omp_get_level = 1 omp_get_active_level = 1
2> omp_get_level = 2 omp_get_active_level = 2
2> omp_get_level = 2 omp_get_active_level = 2
2> omp_get_level = 2 omp_get_active_level = 2
2> omp_get_level = 2 omp_get_active_level = 2
3> omp_get_level = 3 omp_get_active_level = 3
3> omp_get_level = 3 omp_get_active_level = 3
3> omp_get_level = 3 omp_get_active_level = 3
3> omp_get_level = 3 omp_get_active_level = 3
3> omp_get_level = 3 omp_get_active_level = 3
3> omp_get_level = 3 omp_get_active_level = 3
3> omp_get_level = 3 omp_get_active_level = 3
3> omp_get_level = 3 omp_get_active_level = 3
可以看到 3> 的输出次数等于8,这个次数就表明外部 4 个线程都在第三个并行块产生了两个线程,这就是启动嵌套并行块的效果,这就是设置函数 omp_set_max_active_levels 的效果。
- omp_get_nested,这个函数的作用就是返回是否启动了并行嵌套,在 C 语言当中如果启动了那么就是返回 1,否则就是返回 0。
#include <stdio.h>
#include <omp.h>
int main()
{
printf("omp_get_nested() = %d\n", omp_get_nested());
omp_set_nested(1);
printf("omp_get_nested() = %d\n", omp_get_nested());
return 0;
}
上面的程序的输出结果如下所示:
omp_get_nested() = 0
omp_get_nested() = 1
总结
在本篇文章当中主要给大家介绍了一些在 OpenMP 当中常用的动态库函数,这篇文章的动态库函数主要是关于并行域和线程状态的函数,在下篇文章当中我们主要是分析一些 OpenMP 当中的锁相关函数。希望大家有所收获!
更多精彩内容合集可访问项目:https://github.com/Chang-LeHung/CSCore
关注公众号:一无是处的研究僧,了解更多计算机(Java、Python、计算机系统基础、算法与数据结构)知识。
Openmp Runtime 库函数汇总(上)的更多相关文章
- <转>二十问全链路压测干货汇总(上)
本文转载自:微信公众号-数列科技<二十问全链路压测干货汇总(上)> 最近几年全链路压测无疑成为了一个热门话题,在各个技术峰会上都可以看到它的身影. 一些大型的互联网公司,比如阿里巴巴.京东 ...
- ANDROID内存优化(大汇总——上)
转载请注明本文出自大苞米的博客(http://blog.csdn.net/a396901990),谢谢支持! 写在最前: 本文的思路主要借鉴了2014年AnDevCon开发者大会的一个演讲PPT,加上 ...
- Matlab中插值函数汇总(上)
Matlab中插值函数汇总分上下两个部分,主要整合自matlabsky论坛dynamic发表于2009-2-21 21:53:26 的主题帖,以及豆丁网rickoon上传的教材第8章<插值,拟合 ...
- Runtime ----- 带你上道
在IOS开发和学习过程中,我们经常会接触到一个词: Runtime .很多开发者对之既熟悉又陌生,基本都是浅尝辄止,达不到灵活使用的水平(话说开发中也确实不经常用..)本文和大家一起研究一下,Run ...
- C语言标准库函数(网络上copy的)
C语言标准库函数 标准io函数Standard C I/Oclearerr() clears errorsfclose() close a filefeof() true if at the end- ...
- leetcode - 位运算题目汇总(上)
最近在看位运算的知识,十分感叹于位运算的博大精深,正好leetcode有 Bit Manipulation 的专题,正好拿来练练手. Subsets 给出一个由不同的数字组成的数组,枚举它的子数组(子 ...
- Vs 2008 对 OpenMP 的 支持 以及 OpenMP的环境变量及库函数
Visual C++® 2008对OpenMP的支持 VC++2008根据项目属性配置的指示进行 /openmp编译器切换,当配置了OpenMP支持后,编译器会提供_OPENMP定义,可以使用#ifd ...
- iOS开发-Runtime详解(简书)
简介 Runtime 又叫运行时,是一套底层的 C 语言 API,其为 iOS 内部的核心之一,我们平时编写的 OC 代码,底层都是基于它来实现的.比如: [receiver message]; // ...
- Runtime运行时机制
Runtime 又叫运行时,是一套底层的 C 语言 API,其为 iOS 内部的核心之一,我们平时编写的 OC 代码,底层都是基于它来实现的 我们需要了解的是 Objective-C 是一门动态语言, ...
- C Runtime Library来历, API, MFC, ATL关系
首先说明,我google了半天,想找到英文的关于这个资料,但是实在找不到,只好转载国人的讨论. CRT原先是指Microsoft开发的C Runtime Library,用于操作系统的开发及运行.后来 ...
随机推荐
- 服务器之Apollo单机部署(快速安装)
部署Apollo apollo单机部署(快速安装) Apollo官网:https://www.apolloconfig.com/#/zh/deployment/quick-start-docker 官 ...
- 【高并发】深度解析ScheduledThreadPoolExecutor类的源代码
在[高并发专题]的专栏中,我们深度分析了ThreadPoolExecutor类的源代码,而ScheduledThreadPoolExecutor类是ThreadPoolExecutor类的子类.今天我 ...
- 基于YOLO和PSPNet的目标检测与语义分割系统(python)
基于YOLO和PSPNet的目标检测与语义分割系统 源代码地址 概述 这是我的本科毕业设计 它的主要功能是通过YOLOv5进行目标检测,并使用PSPNet进行语义分割. 本项目YOLOv5部分代码基于 ...
- Sql Server 数据库分页存储过程书写
create proc 存储过程名称( @page int, //pageindex @rows int, //pagesize @rowCount int out)as begin--定义字符串变量 ...
- typora的简单使用
一级标题 #+空格 或者快捷键ctrl+1 二级标题 ##+空格 或者快捷键ctrl+2 三级标题 ###+空格 或者快捷键ctrl+3 调试模式 开启调试模式:快捷键shift+F12 字体 Hel ...
- SqlDataAdapter使用小结
SqlDataAdapter是 DataSet与SQL Server之间的桥接器,用于相互之间的数据操作. 使用方法 1. 通过查询语句 与 SqlConnection对象实现 string strC ...
- 自动化运维?看看Python怎样完成自动任务调度⛵
作者:韩信子@ShowMeAI Python3◉技能提升系列:https://www.showmeai.tech/tutorials/56 本文地址:https://www.showmeai.tech ...
- 如何快捷地修改虚拟机镜像——libguestfs-tools工具集介绍
前言 在使用云服务器产品时,由于问题修复.功能添加.软件更新等原因,往往需要对已有系统镜像进行二次修改. 这种情况下,最为简单的做法是:使用原镜像创建实例,在实例中进行修改,修改完毕后再转镜像.这种做 ...
- K8Snode节点管理集群资源方法
1.1 方法1 1.将master的admin.conf 文件拷贝到 node节点 [root@k8s-m ~]#scp /etc/kubernetes/admin.conf root@192.168 ...
- MySQL数据库:6、约束的概述及语法
Python基础之MySQL数据库 目录 Python基础之MySQL数据库 一.约束概述 1.为什么要约束 2.什么是约束 3.约束的分类 4.查看当前表已有的约束 二.约束语法及用法 1.无符号 ...