并行程序设计——OMP编程

实验一

实验内容

分别实现课件中的梯形积分法的Pthread、OpenMP版本,熟悉并掌握OpenMP编程方法,探讨两种编程方式的异同。

实验代码

OpenMP编程

#include <stdio.h>
#include <stdlib.h>
#include <omp.h>void Trap(double a, double b, int n, double *global_result_p);double f(double x) {return x * x;
}int main(int argc, char *argv[]) {double global_result = 0.0;double a, b;int n;int thread_count;thread_count = 5;printf("Enter a, b, and n\n");scanf("%lf %lf %d", &a, &b, &n);
# pragma omp parallel num_threads(thread_count)Trap(a, b, n, &global_result);printf("With n = %d trapezoids, our estimate\n", n);printf("of the integral from %f to %f = %.14e\n", a, b, global_result);return 0;
} /* main*/void Trap(double a, double b, int n, double *global_result_p) {double h, x, my_result;double local_a, local_b;int i, local_n;int my_rank = omp_get_thread_num();int thread_count = omp_get_num_threads();h = (b - a) / n;local_n = n / thread_count;local_a = a + my_rank * local_n * h;local_b = local_a + local_n * h;my_result = (f(local_a) + f(local_b)) / 2.0;for (i = 1; i <= local_n; i++) {x = local_a + i * h;my_result += f(x);}my_result = my_result * h;
# pragma omp critical*global_result_p += my_result;
} /* Trap*/

实验效果

pthread编程

#include <pthread.h>
#include <algorithm>
#include <stdio.h>
# include <stdlib.h>double f(double x) {return x * x;
}typedef struct {int threadId;
} threadParm_t;
const int THREAD_NUM = 5; //表示线程的个数
int next_task = 1;//从1开始
int seg = 50;//每次分50份
double totalSize = 0.000; //表示总面积
double h = 0.00;//表示间距
double a = 1.000, b = 8.000;
int n = 1000;
pthread_mutex_t barrier_mutex = PTHREAD_MUTEX_INITIALIZER;void cal(int i) {//计算第i分double x = a + i * h;double myResult = f(x) * h;pthread_mutex_lock(&barrier_mutex);totalSize += myResult;pthread_mutex_unlock(&barrier_mutex);
}void *SSE_pthread(void *parm) {int task = 0;while (true) {pthread_mutex_lock(&barrier_mutex);next_task += seg;task = next_task;pthread_mutex_unlock(&barrier_mutex);if (task - seg >= n) break;for (int i = task - seg; i < std::min(task, n); i++) {cal(i);}}pthread_exit(nullptr);
}int main(int arg, char *argv[]) {pthread_t thread[THREAD_NUM];threadParm_t threadParm[THREAD_NUM];for (int i = 0; i < THREAD_NUM; i++) {threadParm[i].threadId = i;}printf("Enter a, b, and n\n");scanf("%lf %lf %d", &a, &b, &n);//先计算两边的面积之和h = (b - a) / n;totalSize = h * (f(a) + f(b)) / 2;for (int i = 0; i < THREAD_NUM; i++) {pthread_create(&thread[i], nullptr, SSE_pthread, (void *) &threadParm[i]);}for (int k = 0; k < THREAD_NUM; k++) {pthread_join(thread[k], nullptr);}pthread_mutex_destroy(&barrier_mutex);printf("With n = %d trapezoids, our estimate\n", n);printf("of the integral from %f to %f = %.14e\n", a, b, totalSize);return 0;
}

实验结果


注:由于我的pthread求梯形的基准和OpenMP的基准不同,所以求的实验结果略有差异

两种编程方式的异同

OpenMP是根植于编译器的,更偏向于将原来串行化的程序,通过加入一些适当的编译器指令(compiler directive)变成并行执行,从而提高代码运行的速率。这样做是在没有OpenMP支持编译时,代码仍然可以编译。 创建线程等后续工作需要编译器来完成。

Pthread是一个库,所有的并行线程创建都需要我们自己完成。Pthread仅在有多个处理器可用时才对并行化有效,并且仅在代码针对可用处理器数进行了优化时才有效。 因此,OpenMP的代码更易于扩展。

实验二

实验描述

对于课件中“多个数组排序”的任务不均衡案例进行OpenMP编程实现(规模可自己调整),并探索不同循环调度方案的优劣。提示:可从任务分块的大小、线程数的多少、静态动态多线程结合等方面进行尝试,探索规律。

实验代码

#include <stdio.h>
#include <stdlib.h>
#include <omp.h>
#include <ctime>
#include <sys/time.h>
#include <algorithm>const int ARR_NUM = 1000; //固定数组大小
const int ARR_LEN = 4000; //固定数组长度
int THREAD_NUM = 4; //固定线程个数,改变粗颗粒分配大小
int seg = 10; //改变粗颗粒的分配大小
struct timeval startTime, stopTime;// timers
int arr[ARR_NUM][ARR_LEN];
int tempArr[ARR_NUM][ARR_LEN]; //用于暂时存储数组,控制变量唯一
int next_arr = 0;void OMP_sort();void init(int num) {srand(unsigned(time(nullptr)));for (int i = 0; i < num; i++) {for (int j = 0; j < ARR_LEN; j++)arr[i][j] = rand();}
}//使用冒泡排序,使变量唯一
void sort(int *a) {for (int i = 0; i < ARR_LEN - 1; ++i) {for (int j = i + 1; j < ARR_LEN; ++j) {if (a[j] < a[i]) {int temp = a[i];a[i] = a[j];a[j] = temp;}}}
}void store(int a[][ARR_LEN], int b[][ARR_LEN], int num) {for (int i = 0; i < num; i++) {for (int j = 0; j < ARR_LEN; j++)b[i][j] = a[i][j];}
}int main(int argc, char *argv[]) {init(ARR_NUM);store(arr, tempArr, ARR_NUM);for (; seg <= 100; seg += 10) {printf("seg: %d\n",seg);store(tempArr, arr, ARR_NUM);next_arr = 0;gettimeofday(&startTime, NULL);
# pragma omp parallel num_threads(THREAD_NUM)OMP_sort();gettimeofday(&stopTime, NULL);double trans_mul_time =(stopTime.tv_sec - startTime.tv_sec) * 1000 + (stopTime.tv_usec - startTime.tv_usec) * 0.001;printf("time :%lf ms\n", trans_mul_time);}return 0;
} /* main*/void OMP_sort() {int task = 0;while (true) {#pragma omp critical //每次只能一个线程执行task = next_arr += seg;//每次动态分配seg个if (task - seg >= ARR_NUM) break;int min = task < ARR_NUM ? task : ARR_NUM;for (int i = task - seg; i < min; ++i) {sort(arr[i]);}}
} /* Trap*/

实验运行结果


如此进行多次重复实验,将得到的数据绘成echarts图表

实验图表和结论

实验结论

  1. 由以上图表可知,根据动态粗颗粒的分配的大小可知,各个分配结果的运行效率基本相似。
  2. 由上图可知,当每次分配数目为30的时候,运行时间最短,运行效率最快。但是当每次分配个数超过80时,运行效率也不低。由于此次实验总的数组的行数比较少,所以运行效率并不会相差很大,如若需要更加准确的数值的话,则需要加大数组的行数。

实验三(附加题)

实验内容

实现高斯消去法解线性方程组的OpenMP编程,与SSE/AVX编程结合,并探索优化任务分配方法。

实验代码

#include <stdio.h>
#include <stdlib.h>
#include <omp.h>
#include <ctime>
#include <sys/time.h>
#include <algorithm>
#include <pmmintrin.h>const int n = 2048;//固定矩阵规模,控制变量
const int maxN = n + 1; // 矩阵的最大值
float a[maxN][maxN];
float temp[maxN][maxN];//用于暂时存储a数组中的变量,控制变量唯一
const int THREAD_NUM = 4; //表示线程的个数
int seg = 30;//表示每次线程运行的行数,将来它会改变来探究最优任务分配方法
int next_task = 0;
int line = 0;//记录当前所依赖的行数
struct timeval startTime, stopTime;// timers/*** 根据第i行的元素,消除j行的元素* @param i 根据的行数* @param j 要消元的行数*/
void OMP_elimination(int i, int j) {float tep;__m128 div, t1, t2, sub;// 用temp暂存相差的倍数tep = a[j][i] / a[i][i];// div全部用于存储temp,方便后面计算div = _mm_set1_ps(tep);//每四个一组进行计算,思想和串行类似int k = n - 3;for (; k >= i + 1; k -= 4) {t1 = _mm_loadu_ps(a[i] + k);t2 = _mm_loadu_ps(a[j] + k);sub = _mm_sub_ps(t2, _mm_mul_ps(t1, div));_mm_store_ss(a[j] + k, sub);}//处理剩余部分for (k += 3; k >= i + 1; --k) {a[j][k] -= a[i][k] * tep;}a[j][i] = 0.00;
}/*** 多线程消元函数,动态粗颗粒分配,每次分配seg个* @param parm*/
void OMP_func() {int task = 0;while (true) {#pragma omp critical //每次只能一个线程执行{task = next_task;next_task += seg;//每次分配seg个}if (task >= n) break;int min = task + seg < n ? task + seg : n;for (int i = task; i < min; ++i) {OMP_elimination(line, i);}}
}//用于矩阵改变数值,为防止数据溢出,随机数的区间为100以内的浮点数
void change() {srand((unsigned) time(NULL));for (int i = 0; i < n; i++) {for (int j = 0; j <= n; j++) {a[i][j] = (float) (rand() % 10000) / 100.00;}}
}/*** 将a数组的数据存储到b数组中* @param a* @param b*/
void store(float a[][maxN], float b[][maxN]) {for (int i = 0; i < n; i++) {for (int j = 0; j <= n; j++) {b[i][j] = a[i][j];}}
}int main(int arg, char *argv[]) {change();store(a, temp);// SSE算法消元设计for (; seg <= 300; seg += 30) {store(temp, a);//从temp中取数printf("seg: %d\n", seg);gettimeofday(&startTime, NULL);for (line = 0; line < n - 1; ++line) {next_task = line + 1;
# pragma omp parallel num_threads(THREAD_NUM)OMP_func();}gettimeofday(&stopTime, NULL);double trans_mul_time =(stopTime.tv_sec - startTime.tv_sec) * 1000 + (stopTime.tv_usec - startTime.tv_usec) * 0.001;printf("time: %lf ms\n", trans_mul_time);}
}

代码运行结果

如此重复多次实验,将所得到的的数据绘成echarts图表

实验图表和结论


实验结论

  1. 与上个实验不同的是,这次实验我增加了整体矩阵的大小和每次分配行数的间距,这样得出的实验结果更加准确。
  2. 由上图表可知,当矩阵规模达到2048×\times× 2048时,整体运行的运行时间都相对较短,运行效率相比于串行化执行要快很多。每次分配90行的时候运行效果最佳,180~240的时候与90相差不大,整体区别不太。所以矩阵规模越大,尽量分配越多的行数使运行效率加快。

并行程序设计——OMP编程相关推荐

  1. CUDA并行程序设计 GPU编程指南: 第一章:超级计算简史

  2. c语言mpi并行程序,高性能计算之并行编程技术MPI并行程序设计(完整版).pdf

    高性能计算之并行编程技术MPI并行程序设计(完整版) 高性能计算之并行编程技术 -- MPI并行程序设计 都志辉 编著 李三立 审阅 陈渝 刘鹏 校对 I 内容提要 本书介绍目前最常见的并行程序- M ...

  3. 推荐书籍:CUDA并行程序设计:GPU编程指南

    过去的五年中,计算领域目睹了英伟达(NVIDIA)公司带来的变革.随后的几年,英伟达公司异军突起,逐渐成长为最知名的游戏硬件制造商之一.计算统一设备架构(Compute Unified Device ...

  4. 奥鹏20春季1903C语言,奥鹏20春学期《并行程序设计》在线作业

    1,n个数求和的串行程序,通过一个循环将每个数累加到全局变量sum中,其多线程版本简单将循环范围改变为每 个线程负载的范围,存在的问题是____. A 负载不均 B 通信开销大 C CPU空闲等待严重 ...

  5. 基于mpi的奇偶排序_并行程序设计(第2版)pdf

    并行程序设计(第2版) 内容简介 本书系统介绍并行程序设计原理及应用.除介绍常用的一些算法范例,包括分治.流水.同步计算.主从及工作池,还介绍了一些常用的经典数值和非数值算法,如排序.矩阵相乘.线性方 ...

  6. Nvidia CUDA初级教程2 并行程序设计概述

    Nvidia CUDA初级教程2 并行程序设计概述 视频:https://www.bilibili.com/video/BV1kx411m7Fk?p=3 讲师:周斌 本节内容: 为什么需要? 怎么做? ...

  7. linux线程并不真正并行,多核时代:并行程序设计探讨(3)——Windows和Linux对决(多进程多线程)...

    并行程序设计探讨(3)--Windows和Linux对决(多进程多线程) 前面的博文经过分析总结,最后得出两种并行技术:多进程多线程.多机协作.对于多进程和多线程来说,最有代表性且最常见的的莫过于Wi ...

  8. OpenMP 并行程序设计入门

    OpenMP 是一个编译器指令和库函数的集合,主要是为共享式存储计算机上的并行程序设计使用的. 0. 一段使用 OpenMP 的并行程序 #include <stdio.h> #inclu ...

  9. 并行程序设计导论_C程序设计导论

    并行程序设计导论 基本术语 (Basic Terminology) Before we start the technicalities of our topic, let us understand ...

最新文章

  1. C++ 引用类型简介
  2. java基本语文档_Java 文档注释
  3. js压缩代码后怎么生成source map_??markdown生成导航? #x27;[toc]#x27;足矣
  4. 技术回顾系列:最新最热门的技术大事-第一周
  5. 发现不错的文章,推!
  6. 启动tomcat遇到的问题整理
  7. Nginx不停机优雅升级
  8. CC++中的qsort库函数
  9. sql server死锁_如何解决SQL Server中的死锁
  10. struts2(2012/2/24)
  11. Hive jdbc执行seelct 语句时报 return code 1 from org.apache.hadoop.hive.ql.exec.mr.MapRedTask
  12. oracle var/tmp,[20141128]目录/var/tmp/oracle.txt
  13. Win11系统如何打开地雷游戏 Win11打开扫雷游戏的教程
  14. 机器学习基础(二)——词集模型(SOW)和词袋模型(BOW)
  15. clodop配置SSL证书 WEB打印机服务
  16. artDialog | 经典的网页对话框组件
  17. PLC可编程控制器、单片机开发应用及电气控制综合实训装置
  18. 使用 HttpWatch 分析 HTTP 协议
  19. 华为“吐出”的高端市场,小米 Ov 却吃不下
  20. 【ROM制作工具】小白如何进行ROM解包,精简,修改,授权,打包详细图文教程...

热门文章

  1. java android程序代码_用java 代码读取android应用的一些基本信息
  2. matplotlib 简单入门
  3. JavaSwing人事管理系统(Java课程设计)
  4. Vue中html全屏背景色(height:100%不能生效时)
  5. js实现二维码携带参数
  6. 转的心服口服,工程郎难道真的单身?
  7. vue导出pdf文件
  8. Node.js 应用高 CPU 占用率的分析方法
  9. 关于squid禁止某些站点的访问的控制 (acl语句)
  10. Python 二分查找与方程求解(公开代码)