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 库函数汇总(上)的更多相关文章

  1. <转>二十问全链路压测干货汇总(上)

    本文转载自:微信公众号-数列科技<二十问全链路压测干货汇总(上)> 最近几年全链路压测无疑成为了一个热门话题,在各个技术峰会上都可以看到它的身影. 一些大型的互联网公司,比如阿里巴巴.京东 ...

  2. ANDROID内存优化(大汇总——上)

    转载请注明本文出自大苞米的博客(http://blog.csdn.net/a396901990),谢谢支持! 写在最前: 本文的思路主要借鉴了2014年AnDevCon开发者大会的一个演讲PPT,加上 ...

  3. Matlab中插值函数汇总(上)

    Matlab中插值函数汇总分上下两个部分,主要整合自matlabsky论坛dynamic发表于2009-2-21 21:53:26 的主题帖,以及豆丁网rickoon上传的教材第8章<插值,拟合 ...

  4. Runtime ----- 带你上道

    在IOS开发和学习过程中,我们经常会接触到一个词: Runtime  .很多开发者对之既熟悉又陌生,基本都是浅尝辄止,达不到灵活使用的水平(话说开发中也确实不经常用..)本文和大家一起研究一下,Run ...

  5. C语言标准库函数(网络上copy的)

    C语言标准库函数 标准io函数Standard C I/Oclearerr() clears errorsfclose() close a filefeof() true if at the end- ...

  6. leetcode - 位运算题目汇总(上)

    最近在看位运算的知识,十分感叹于位运算的博大精深,正好leetcode有 Bit Manipulation 的专题,正好拿来练练手. Subsets 给出一个由不同的数字组成的数组,枚举它的子数组(子 ...

  7. Vs 2008 对 OpenMP 的 支持 以及 OpenMP的环境变量及库函数

    Visual C++® 2008对OpenMP的支持 VC++2008根据项目属性配置的指示进行 /openmp编译器切换,当配置了OpenMP支持后,编译器会提供_OPENMP定义,可以使用#ifd ...

  8. iOS开发-Runtime详解(简书)

    简介 Runtime 又叫运行时,是一套底层的 C 语言 API,其为 iOS 内部的核心之一,我们平时编写的 OC 代码,底层都是基于它来实现的.比如: [receiver message]; // ...

  9. Runtime运行时机制

    Runtime 又叫运行时,是一套底层的 C 语言 API,其为 iOS 内部的核心之一,我们平时编写的 OC 代码,底层都是基于它来实现的 我们需要了解的是 Objective-C 是一门动态语言, ...

  10. C Runtime Library来历, API, MFC, ATL关系

    首先说明,我google了半天,想找到英文的关于这个资料,但是实在找不到,只好转载国人的讨论. CRT原先是指Microsoft开发的C Runtime Library,用于操作系统的开发及运行.后来 ...

随机推荐

  1. Redis 常见问题-缓存穿透

    问题描述: * 针对 DB 中不存在的数据源,每次请求缓存和数据库都不存在 造成后果: * 应用服务器压力变大 * Redis 命中率大幅度降低 * `数据库压力巨增甚至 down 掉`* 该现象对于 ...

  2. 如何在 Inno Setup 中关联多种文件格式

    问题描述 Inno Setup 是一款十分强大的 Windows 安装程序制作软件,可以通过编写并编译 iss 脚本来创建安装包.之前都是直接将 Pyinstaller 生成的文件夹压缩为 zip 格 ...

  3. perl之grep函数的用法

    转载至 perl中grep的详细用法 grep有2种表达方式: 1 grep BLOCK LIST 2 grep EXPR, LIST BLOCK表示一个code块,通常用{}表示:EXPR表示一个表 ...

  4. mybatis中association和collection使用

    mybatis中association和collection使用 一.概述 association:一个复杂的类型关联.许多结果将包成这种类型 collection:复杂类型的集合 这2个属性的使用, ...

  5. 本地GoLand编辑与调试远端服务器上的代码

    Goland是专为Go开发人员构建的跨平台IDE,功能非常强大,拥有强大的代码洞察力,帮助所有Go开发人员即时错误检测和修复建议,快速和安全的重构,一步撤销,智能代码完成,死代码检测和文档提示,让您创 ...

  6. 学习ASP.NET Core Blazor编程系列十四——修改

    学习ASP.NET Core Blazor编程系列一--综述 学习ASP.NET Core Blazor编程系列二--第一个Blazor应用程序(上) 学习ASP.NET Core Blazor编程系 ...

  7. day07 方法重写&super、this、static关键字&JVM的类加载顺序题目

    day07 方法重写 1)重写发生在子父类当中 2)方法名.参数列表.返回值均相同 3)重写的方法,方法体或者访问控制修饰符不同 4)子类方法的访问权限不能缩小,比如父类是int,子类重写权限不能是b ...

  8. MybatisPlus多表连接查询一对多分页查询数据

    一.序言 在日常一线开发过程中,多表连接查询不可或缺,基于MybatisPlus多表连接查询究竟该如何实现,本文将带你找到答案. 在多表连接查询中,既有查询单条记录的情况,又有列表查询,还有分页查询, ...

  9. Flink SQL管理平台flink-streaming-platform-web安装搭建

    文章都在个人博客网站:https://www.ikeguang.com/ 同步,欢迎访问. 最近看到有人在用flink sql的页面管理平台,大致看了下,尝试安装使用,比原生的flink sql界面确 ...

  10. 18V转5V,15V转5V的LDO和DC芯片方案

    18V 转 5V, 15V 转 5V 的 LDO:芯片的选择,特别是输入电压,在低电平 5V 以下的,基本上都是接近也可以.但是 5V 以上,如现在的 18V 和 15 的话,就不一样了.我们需要在选 ...