一 OpenMP 教程 深入人剖析 OpenMP reduction 子句( 二 )


如果有 4 个线程的话,那么就有 4 个线程本地的 data(每个线程一个 data) 。那么规约(reduction)操作的结果等于:
(((data1 + data2) + data3) + data4) 其中 datai 表示第 i 个线程的得到的 data。
除了后面的两种方法解决多个线程同时对一个数据进行操作的问题的之外我们还有一些其他的办法去解决这个问题,我们在下一篇文章当中进行仔细分析 。
深入剖析 reduction 子句我们在写多线程程序的时候可能会存在这种需求,每个线程都会得到一个数据的结果,然后在最后需要将每个线程得到的数据进行求和,相乘,或者逻辑操作等等,在这种情况下我们可以使用 reduction 子句进行操作 。redcution 子句的语法格式如下:
reduction(操作符:变量)当我们使用 reduction 子句的时候线程使用的是与外部变量同名的变量,那么这个同名的变量的初始值应该设置成什么呢?具体的设置规则如下所示:
运算符初始值+/加法0*/乘法1&&/逻辑与1||/逻辑或0min/最小值对应类型的最大值max/最大值对应类型的最小值&/按位与所有位都是 1|/按位或所有位都是 0^/按位异或所有位都是 0下面我们使用各种不同的例子去分析上面的所有的条目:
加法+操作符我们使用下面的程序去测试使用加法规约的正确性,并且在并行域当中打印进行并行域之前变量的值 。
#include <stdio.h>#include <omp.h>static int data;int main() {#pragma omp parallel num_threads(2) reduction(+:data){printf("初始值 : data = https://www.huyubaike.com/biancheng/%d tid = %d/n", data, omp_get_thread_num());if(omp_get_thread_num() == 0) {data = https://www.huyubaike.com/biancheng/10;}else if(omp_get_thread_num() == 1){data = 20;}printf("变化后的值 : data = https://www.huyubaike.com/biancheng/%d tid = %d/n", data, omp_get_thread_num());}printf("规约之后的值 : data = https://www.huyubaike.com/biancheng/%d/n", data);return 0;}上面的程序的输出结果如下所示:
初始值 : data = https://www.huyubaike.com/biancheng/0 tid = 0变化后的值 : data = 10 tid = 0初始值 : data = 0 tid = 1变化后的值 : data = 20 tid = 1规约之后的值 : data = 30从上面的输出结果我们可以知道当进入并行域之后我们的变量的初始值等于 0  , 第一个线程的线程 id 号等于 0  , 它将 data 的值赋值成 10,第二个线程的线程 id 号 等于 1,它将 data 的值赋值成 20。在出并行域之前会将两个线程得到的 data 值进行规约操作,在上面的代码当中也就是+操作,并且将这个值赋值给全局变量 data。
乘法*操作符#include <stdio.h>#include <omp.h>static int data = https://www.huyubaike.com/biancheng/2;int main() {#pragma omp parallel num_threads(2) reduction(*:data){printf("初始值 : data = https://www.huyubaike.com/biancheng/%d tid = %d/n", data, omp_get_thread_num());if(omp_get_thread_num() == 0) {data = https://www.huyubaike.com/biancheng/10;}else if(omp_get_thread_num() == 1){data = 20;}printf("变化后的值 : data = https://www.huyubaike.com/biancheng/%d tid = %d/n", data, omp_get_thread_num());}printf("规约之后的值 : data = https://www.huyubaike.com/biancheng/%d/n", data);return 0;}上面的程序输出结果如下所示:
初始值 : data = https://www.huyubaike.com/biancheng/1 tid = 0变化后的值 : data = 10 tid = 0初始值 : data = 1 tid = 1变化后的值 : data = 20 tid = 1规约之后的值 : data = 400从上面的程序的输出结果来看,当我们使用*操作符的时候,我们可以看到程序当中 data 的初始值确实被初始化成了 1,而且最终在主函数当中的输出结果也是符合预期的,因为 400 = 2 * 10 * 20 , 其中 2 只在全局变量初始化的时候的值 。
逻辑与&&操作符#include <stdio.h>#include <omp.h>static int data = https://www.huyubaike.com/biancheng/100;int main() {#pragma omp parallel num_threads(2) reduction(&&:data){printf("data =https://www.huyubaike.com/t %d tid = %d/n", data, omp_get_thread_num());if(omp_get_thread_num() == 0) {data = https://www.huyubaike.com/biancheng/10;}else if(omp_get_thread_num() == 1){data = 20;}}printf("data = https://www.huyubaike.com/biancheng/%d/n", data);return 0;}【一 OpenMP 教程 深入人剖析 OpenMP reduction 子句】上面的程序的输出结果如下所示:
初始化值 : data = https://www.huyubaike.com/biancheng/1 tid = 0初始化值 : data = 1 tid = 1在主函数当中 : data = 1从上面的输出结果我们可以知道 , 程序当中数据的初始化的值是没有问题的 , 你可能会疑惑为什么主函数当中的 data 值等于 1,这其实就是 C 语言当中对 && 操作服的定义,如果最终的结果为真,那么值就等于 1,即 100 && 10 && 20 == 1 , 你可以写一个程序去验证这一点 。

推荐阅读