OpenMP Sections Construct 实现原理以及源码分析

前言

在本篇文章当中主要给大家介绍 OpenMP 当中主要给大家介绍 OpenMP 当中 sections construct 的实现原理以及他调用的动态库函数分析。如果已经了解过了前面的关于 for 的调度方式的分析,本篇文章就非常简单了。

编译器角度分析

在这一小节当中我们将从编译器角度去分析编译器会怎么处理 sections construct ,我们以下面的 sections construct 为例子,看看编译器是如何处理 sections construct 的。

#pragma omp sections
{
#pragma omp section
stmt1;
#pragma omp section
stmt2;
#pragma omp section
stmt3;
}

上面的代码会被编译器转换成下面的形式,其中 GOMP_sections_start 和 GOMP_sections_next 是并发安全的,他们都会返回一个数据表示第几个 omp section 代码块,其中 GOMP_sections_start 的参数是表示有几个 omp section 代码块,并且返回给线程一个整数表示线程需要执行第几个 section 代码块,这两个函数的意义不同的是在 GOMP_sections_start 当中会进行一些数据的初始化操作。当两个函数返回 0 的时候表示所有的 section 都被执行完了,从而退出 for 循环。

for (i = GOMP_sections_start (3); i != 0; i = GOMP_sections_next ())
switch (i)
{
case 1:
stmt1;
break;
case 2:
stmt2;
break;
case 3:
stmt3;
break;
}
GOMP_barrier ();

动态库函数分析

事实上在函数 GOMP_sections_start 和函数 GOMP_sections_next 当中调用的都是我们之前分析过的函数 gomp_iter_dynamic_next ,这个函数实际上就是让线程始终原子指令去竞争数据块(chunk),这个特点和 sections 需要完成的语意是相同的,只不过 sections 的块大小(chunk size)都是等于 1 的,因为一个线程一次只能够执行一个 section 代码块。

unsigned
GOMP_sections_start (unsigned count)
{
// 参数 count 的含义就是表示一共有多少个 section 代码块
// 得到当线程的相关数据
struct gomp_thread *thr = gomp_thread ();
long s, e, ret;
// 进行数据的初始化操作
// 将数据的 chunk size 设置等于 1
// 分割 chunk size 的起始位置设置成 1 因为根据上面的代码分析 0 表示退出循环 因此不能够使用 0 作为分割的起始位置
if (gomp_work_share_start (false))
{
// 这里传入 count 作为参数的原因是需要设置 chunk 分配的最终位置 具体的源代码在下方
gomp_sections_init (thr->ts.work_share, count);
gomp_work_share_init_done ();
}
// 如果获取到一个 section 的执行权 gomp_iter_dynamic_next 返回 true 否则返回 false
// s 和 e 分别表示 chunk 的起始位置和终止位置 但是在 sections 当中需要注意的是所有的 chunk size 都等于 1
// 这也很容易理解一次执行一个 section 代码块
if (gomp_iter_dynamic_next (&s, &e))
ret = s;
else
ret = 0;
return ret;
} // 下面是部分 gomp_sections_init 的代码
static inline void
gomp_sections_init (struct gomp_work_share *ws, unsigned count)
{
ws->sched = GFS_DYNAMIC;
ws->chunk_size = 1; // 设置 chunk size 等于 1
ws->end = count + 1L; // 因为一共有 count 个 section 块
ws->incr = 1; // 每次增长一个
ws->next = 1; // 从 1 开始进行 chunk size 的分配 因为 0 表示退出循环(编译器角度分析)
} unsigned
GOMP_sections_next (void)
{
// 这个函数就比较容易理解了 就是获取一个 chunk 拿到对应的 section 的执行权
long s, e, ret;
if (gomp_iter_dynamic_next (&s, &e))
ret = s;
else
ret = 0;
return ret;
} // 下面的函数在之前的很多文章当中都分析过了 这里不再进行分析
// 下面的函数的主要过程就是使用 CAS 指令不断的进行尝试,直到获取成功或者全部获取完成 没有 chunk 需要分配
bool
gomp_iter_dynamic_next (long *pstart, long *pend)
{
struct gomp_thread *thr = gomp_thread ();
struct gomp_work_share *ws = thr->ts.work_share;
long start, end, nend, chunk, incr; end = ws->end;
incr = ws->incr;
chunk = ws->chunk_size; if (__builtin_expect (ws->mode, 1))
{
long tmp = __sync_fetch_and_add (&ws->next, chunk);
if (incr > 0)
{
if (tmp >= end)
return false;
nend = tmp + chunk;
if (nend > end)
nend = end;
*pstart = tmp;
*pend = nend;
return true;
}
else
{
if (tmp <= end)
return false;
nend = tmp + chunk;
if (nend < end)
nend = end;
*pstart = tmp;
*pend = nend;
return true;
}
} start = ws->next;
while (1)
{
long left = end - start;
long tmp; if (start == end)
return false; if (incr < 0)
{
if (chunk < left)
chunk = left;
}
else
{
if (chunk > left)
chunk = left;
}
nend = start + chunk; tmp = __sync_val_compare_and_swap (&ws->next, start, nend);
if (__builtin_expect (tmp == start, 1))
break; start = tmp;
} *pstart = start;
*pend = nend;
return true;
}

总结

在本篇文章当中主要介绍了 OpenMP 当中 sections 的实现原理和相关的动态库函数分析,关于 sections 重点在编译器会如何对 sections 的编译指导语句进行处理的,动态库函数和 for 循环的动态调度方式是一样的,只不过 chunk size 设置成 1,分块的起始位置等于 1,分块的最终值是 section 代码块的个数,最终在动态调度的方式使用 CAS 不断获取 section 的执行权,指导所有的 section 被执行完成。


更多精彩内容合集可访问项目:https://github.com/Chang-LeHung/CSCore

关注公众号:一无是处的研究僧,了解更多计算机(Java、Python、计算机系统基础、算法与数据结构)知识。

OpenMP Sections Construct 实现原理以及源码分析的更多相关文章

  1. OpenMP Parallel Construct 实现原理与源码分析

    OpenMP Parallel Construct 实现原理与源码分析 前言 在本篇文章当中我们将主要分析 OpenMP 当中的 parallel construct 具体时如何实现的,以及这个 co ...

  2. OpenMP 线程同步 Construct 实现原理以及源码分析(上)

    OpenMP 线程同步 Construct 实现原理以及源码分析(上) 前言 在本篇文章当中主要给大家介绍在 OpenMP 当中使用的一些同步的 construct 的实现原理,如 master, s ...

  3. OpenMP 线程同步 Construct 实现原理以及源码分析(下)

    OpenMP 线程同步 Construct 实现原理以及源码分析(下) 前言 在上面文章当中我们主要分析了 flush, critical, master 这三个 construct 的实现原理.在本 ...

  4. OpenCV学习笔记(27)KAZE 算法原理与源码分析(一)非线性扩散滤波

    http://blog.csdn.net/chenyusiyuan/article/details/8710462 OpenCV学习笔记(27)KAZE 算法原理与源码分析(一)非线性扩散滤波 201 ...

  5. ConcurrentHashMap实现原理及源码分析

    ConcurrentHashMap实现原理 ConcurrentHashMap源码分析 总结 ConcurrentHashMap是Java并发包中提供的一个线程安全且高效的HashMap实现(若对Ha ...

  6. HashMap和ConcurrentHashMap实现原理及源码分析

    HashMap实现原理及源码分析 哈希表(hash table)也叫散列表,是一种非常重要的数据结构,应用场景及其丰富,许多缓存技术(比如memcached)的核心其实就是在内存中维护一张大的哈希表, ...

  7. (转)ReentrantLock实现原理及源码分析

    背景:ReetrantLock底层是基于AQS实现的(CAS+CHL),有公平和非公平两种区别. 这种底层机制,很有必要通过跟踪源码来进行分析. 参考 ReentrantLock实现原理及源码分析 源 ...

  8. 【转】HashMap实现原理及源码分析

    哈希表(hash table)也叫散列表,是一种非常重要的数据结构,应用场景极其丰富,许多缓存技术(比如memcached)的核心其实就是在内存中维护一张大的哈希表,而HashMap的实现原理也常常出 ...

  9. 【OpenCV】SIFT原理与源码分析:DoG尺度空间构造

    原文地址:http://blog.csdn.net/xiaowei_cqu/article/details/8067881 尺度空间理论   自然界中的物体随着观测尺度不同有不同的表现形态.例如我们形 ...

  10. 《深入探索Netty原理及源码分析》文集小结

    <深入探索Netty原理及源码分析>文集小结 https://www.jianshu.com/p/239a196152de

随机推荐

  1. 硬核!Apache Hudi Schema演变深度分析与应用

    1.场景需求 在医疗场景下,涉及到的业务库有几十个,可能有上万张表要做实时入湖,其中还有某些库的表结构修改操作是通过业务人员在网页手工实现,自由度较高,导致整体上存在非常多的新增列,删除列,改列名的情 ...

  2. python选课系统项目详解

    选课系统项目详解 选课系统简介及分析 选课系统架构设计分析 选课系统目录设计 管理员视图 注册 登录 创建学校 创建课程 创建讲师 学生视图 注册 登录 选择学校 选择课程 查看分数 教师视图 登录 ...

  3. python-py文件打包成exe可执行文件

    方法一::打包完成后可以直接被他人使用,他人不用安装python环境的 可以使用pyinstaller模块实现将python项目打包成exe执行文件 """ 先安装模块 ...

  4. Java语言进阶 day02【Collection、泛型】

    主要内容 Collection集合 迭代器 增强for 泛型 教学目标

  5. npm设置

    1.默认安装完node.js后会自己安装npm,通过npm下载全局模块默认安装到C:\Users\wangyc\AppData\Roaming目录下,主要有两个文件夹:npm.npm-cache 2. ...

  6. Python报AttributeError: module 'string' has no attribute 'join'解决方法

    报:AttributeError: module 'string' has no attribute 'join' 属性错误:模块"string"没有属性"join&qu ...

  7. virtualenv 配置(windows)

    1.在线安装 virtualenv pip install virtualenv 2.离线安装 下载virtualenv包,解压并进入setup.py所在文件夹中 python setup.py in ...

  8. python从公众号文章中获取二维码

    在做一个公众号采集的项目中,客户有个要求,想把二维码的url保存到数据库中,如图. 原本以为要各种骚操作各种逆向才能获取得到,没想到竟然很简单. 第一步 观察二维码url的规范 https://mp. ...

  9. 快速排序算法实现 (y总课后)

    主要思路: 1.确定 边界 l----------r  (left right) 2.确定中间值  l--------x----------r 3.优雅快排: 设置两个指针i,j. i从左边开始运行 ...

  10. 初识argparse 模块

    # 1引入模块 import argparse # 2建立解析对象 parser = argparse.ArgumentParser() # 3增加属性:给xx实例增加一个aa属性 # xx.add_ ...