关于openmp:OpenMP-task-construct-实现原理以及源码分析
OpenMP task construct 实现原理以及源码剖析前言在本篇文章当中次要给大家介绍在 OpenMP 当中 task 的实现原理,以及他调用的相干的库函数的具体实现。在本篇文章当中最重要的就是了解整个 OpenMP 的运行机制。 从编译器角度看 task construct在本大节当中次要给大家剖析一下编译器将 openmp 的 task construct 编译成什么样子,上面是一个 OpenMP 的 task 程序例子: #include <stdio.h>#include <omp.h>int main(){#pragma omp parallel num_threads(4) default(none) {#pragma omp task default(none) { printf("Hello World from tid = %d\n", omp_get_thread_num()); } } return 0;}首先先捋一下整个程序被编译之后的执行流程,通过后面的文章的学习,咱们曾经晓得了并行域当中的代码会被编译器编译成一个函数,对于这一点咱们曾经在后面的很多文章当中曾经探讨过了,就不再进行复述。事实上 task construct 和 parallel construct 一样,task construct 也会被编译成一个函数,同样的这个函数也会被作为一个参数传递给 OpenMP 外部,被传递的这个函数可能被立刻执行,也可能在函数 GOMP_parallel_end 被调用后,在达到同步点之前执行被执行(线程在达到并行域的同步点之前须要保障所有的工作都被执行实现)。整个过程大抵如下图所示: 下面的 OpenMP task 程序对应的反汇编程序如下所示: 00000000004008ad <main>: 4008ad: 55 push %rbp 4008ae: 48 89 e5 mov %rsp,%rbp 4008b1: ba 04 00 00 00 mov $0x4,%edx 4008b6: be 00 00 00 00 mov $0x0,%esi 4008bb: bf db 08 40 00 mov $0x4008db,%edi 4008c0: e8 8b fe ff ff callq 400750 <GOMP_parallel_start@plt> 4008c5: bf 00 00 00 00 mov $0x0,%edi 4008ca: e8 0c 00 00 00 callq 4008db <main._omp_fn.0> 4008cf: e8 8c fe ff ff callq 400760 <GOMP_parallel_end@plt> 4008d4: b8 00 00 00 00 mov $0x0,%eax 4008d9: 5d pop %rbp 4008da: c3 retq00000000004008db <main._omp_fn.0>: 4008db: 55 push %rbp 4008dc: 48 89 e5 mov %rsp,%rbp 4008df: 48 83 ec 10 sub $0x10,%rsp 4008e3: 48 89 7d f8 mov %rdi,-0x8(%rbp) 4008e7: c7 04 24 00 00 00 00 movl $0x0,(%rsp) # 参数 flags 4008ee: 41 b9 01 00 00 00 mov $0x1,%r9d # 参数 if_clause 4008f4: 41 b8 01 00 00 00 mov $0x1,%r8d # 参数 arg_align 4008fa: b9 00 00 00 00 mov $0x0,%ecx # 参数 arg_size 4008ff: ba 00 00 00 00 mov $0x0,%edx # 参数 cpyfn 400904: be 00 00 00 00 mov $0x0,%esi # 参数 data 400909: bf 15 09 40 00 mov $0x400915,%edi # 这里就是调用函数 main._omp_fn.1 40090e: e8 9d fe ff ff callq 4007b0 <GOMP_task@plt> 400913: c9 leaveq 400914: c3 retq0000000000400915 <main._omp_fn.1>: 400915: 55 push %rbp 400916: 48 89 e5 mov %rsp,%rbp 400919: 48 83 ec 10 sub $0x10,%rsp 40091d: 48 89 7d f8 mov %rdi,-0x8(%rbp) 400921: e8 4a fe ff ff callq 400770 <omp_get_thread_num@plt> 400926: 89 c6 mov %eax,%esi 400928: bf d0 09 40 00 mov $0x4009d0,%edi 40092d: b8 00 00 00 00 mov $0x0,%eax 400932: e8 49 fe ff ff callq 400780 <printf@plt> 400937: c9 leaveq 400938: c3 retq 400939: 0f 1f 80 00 00 00 00 nopl 0x0(%rax)从下面程序反汇编的后果咱们能够晓得,在主函数当中依然和之前一样在并行域前后别离调用了 GOMP_parallel_start 和 GOMP_parallel_end,而后在两个函数之间调用并行域的代码 main.\_omp\_fn.0 ,并行域当中的代码被编译成函数 main.\_omp\_fn.0 ,从下面的汇编代码咱们能够看到在函数 main.\_omp\_fn.0 调用了函数 GOMP_task ,这个函数的函数申明如下所示: ...