咱们马上开始,这个“任务循环”结构是被新添加到4.5版本之中的,如名所示,允许分割迭代循环到任务,它能随意的等待完成哪些任务并且每个被创建的任务都可以分配1个或多个迭代循环。例如:
#pragma omp taskloop num_tasks (32) for (long l = 0; l < 1024; l++) do_something (l);
上面的代码将在一个任务组中创建32项相互关系的任务,还有一项合理的实施就是给每项任务分配32次迭代。因为有一个隐式的课题在那里面,我们遇到的任务将依赖其它所有任务的完成。在OpenMP 4.0和更早的版本里,为了实现类似的效果,我们必须手动完成那些任务,像下面的例子:
#pragma omp taskgroup { for (int tmp = 0; tmp < 32; tmp++) #pragma omp task for (long l = tmp * 32; l < tmp * 32 + 32; l++) do_something (l); }
当代码中有很多死循环或者如果在循环中使用C++迭代器时,我们手动处理将会变得越来越困难,所以运用任务循环概念将会大大简化代码源。我们可以使用grainsize措施,而不是指定我们应该创建的任务数目。它指定了每项任务中应该有多少次的迭代(从指定的grain-size到小于它两倍的值),并且这个措施可以自动计算任务的的数目。另外,如果num_tasks和grainsize选项都不见了,这个措施里会选择一些适宜的默认选项。
OpenMP4.5中另一个任务分配的改变是增加了任务优先级, 可以用priority子句指定任务的优先级。正如你所预见的,任务优先级更高的任务将被优先调度。
交叉并行
一些样例考虑对有内部迭代依赖的循环进行并行化。这通常是可行的,只要并行工作的线程不会花费大部分的时间等待其他线程。
OpenMP 4和更早的版本提出的“有序”的构建。在一个循环结构中,以一个ordered子句为标记,将有序结构的主体在循环中执行。OpenMP 4.5可以使用命令(无本体)表示依赖于以前版本的迭代循环,所有其他的迭代可能取决于一个迭代的数据计算。例如:
#pragma omp for ordered(2) for (int i = 0; i < M; i++) for (int j = 0; j < N; j++) { a[i][j] = foo (i, j); #pragma omp ordered depend (sink: i - 1, j) depend (sink: i, j - 1) b[i][j] = bar (a[i][j], b[i - 1][j], b[i][j - 1]); #pragma omp ordered depend (source) baz (a[i][j], b[i][j]); }
以上的例子表明,只有外部循环分布在一组线程中。第一个ordered的指令告诉运行时等待指定的早期迭代完成,而最后一个ordered的指令标志着循环计算出的所有数据的其他循环可能存在依赖。
在这个例子中,编译器会忽视 depend (sink: i, j - 1) 依赖,因为外部循环参与了工作负载,内部循环使用字典顺序迭代;因此,等到 i, j 迭代被执行的时候, i, j – 1迭代肯定就完成了。
除了允许 depend 子句在命令指令中,OpenMP 4.5 还一直允许 threads 和 simd 子句有序构造,还允许 在 SIMD 循环中使用 #pragma omp ordered simd 。这标志着在字典顺序执行代码的区域内 SIMD 循环,对于一小部分代码,不应向量化的 vectorizable 循环。
包括最新的更新,C++参考现在在私有化条款中已经被允许,以前他们只允许共享条款。
C++的方法中,对象的方法调用时,现在对它的非静态数据成员进行私有化访问是有可能的,只要在相应的OpenMP区域中通过使用id-expression(id表达式)来访问,而非显式使用this->memeber来引用。
C和C++中的reduction clause(reduction语块)允许数组区间,因此C/C++的数组可以reduction而无须包装为结构体或是类,也不需要定义用户所定义的reduction。 linear clause(线性语块)现在可以用在循环体中,而此前只允许在SIMD结构中使用。
Offloading 可能是OpenMP标准中变化最大的部分, 由此引入一了些代码级别的不兼容——这些大多与scalar变量的非显式的引用有关,如C/C++对像区域中的指针!
OpenMP 4,这些变量,除非明确在地图条款提到建设目标,进行隐式映射从–意味着指针的主机端值将被复制到目标(通常是不是真的有用,有一个指针)目标值复制到主机(通常也不受欢迎),或最后没有复制如果变量已经映射。
OpenMP 4.5,除非defaultmap(来自:标量)条款使用标量变量是隐式的私有化,如果新firstprivate条款允许建设的目标是让他们使用–意义的值都复制到目标区域,并没有复制回。
在许多情况下,甚至会用OpenMP 4的代码编写工作,但异常主要是如果你需要一个标量值从装置在目标区域的结束。例如,下列OpenMP 4将不再工作:
void foo () { double sum = 0.0; #pragma omp target map(array[0:N]) #pragma omp teams distribute parallel for simd reduction(+:sum) for (int i = 0; i < N; i++) sum += array[i]; return sum; }
失败会因为金额将在该地区firstprivate和主机的值不会被修改。港口代码OpenMP 4.5,需要添加default(tofrom: scalar)
条款的目标区域,或使用显式的map(tofrom: sum)
。
指针是隐式映射为如果他们出现在地图map(ptr[:0])
条款–因此主机指针转化为相应的设备指针如果指向的对象已经映射,或空否则。
C++引用映射已澄清,它现在是可能的地图结构元素单独。异步卸载支持已被添加通过立即和依赖条款对目标构建的,而在OpenMP 4.0,所有目标区域进行同步–主机的任务会等待直到卸载完成后,和一个有使用主机来实现异步任务手动卸载。
目标结构现在被视为一个隐式的任务区域,并添加新的目标输入数据和目标退出数据结构。这意味着映射和映射变量联合国现在可以进行同步或异步,和在不同的函数或方法–例如可以输入数据在C++构造函数和出口数据在C++析构函数。
声明目标指令已被扩展,并且现在可以标记为延迟映射的全局变量(例如大数组)。设备内存例程已经添加显式分配,分配和内存传输主机和卸载设备之间,以及与本地设备实现交互的条款被加入:use_device_ptr条款目标的数据结构和is_device_ptr条款目标构建。
GCC 6目前支持卸载英特尔XeonE5骑士着陆,一些OpenMP 4.5目标构建可卸载到AMD HSA GPGPU,OpenMP卸载Nvidia PTX在作品(OpenACC卸载Nvidia PTX已经支持)。
在OpenMP 4.5 中还有一些较小的改进,包括:
提升了对Fortran 2003 的支持。
关键架构和新提示锁API例程添加了一个hint子句,它允许应用通知运行时资源争用和猜测的必要性。
扩展了if子句,当使用组合和复合构造时,可以指定if子句应用的构造,并且可以对不同构造指定不同的if子句。
在#pragma omp declare simd指令的线性子句中,现在可以通过val,uval和ref修饰指定,不管引用是线性的或引用的变量值是线性的。
查询的线程相关性已经被添加。
在现实中,OpenMP 4.5还包含其他各种小变化,列出了很多说明和bug修复,但是更值得注意的是其中一些总结。
OpenMP 4.5的新版本标准可以从http://www.openmp.org/mp-documents/openmp-4.5.pdf得到,新版本支持即将到来的GCC 6(仅供C和C++。)
Fortran支持的仍然是OpenMP 4.0这个级别的版本,并且计划在今年4月左右发布。
2KB项目(www.2kb.com,源码交易平台),提供担保交易、源码交易、虚拟商品、在家创业、在线创业、任务交易、网站设计、软件设计、网络兼职、站长交易、域名交易、链接买卖、网站交易、广告买卖、站长培训、建站美工等服务