本文共 5286 字,大约阅读时间需要 17 分钟。
匆忙的大三早已结束,时隔两月,再以此文祭奠我炸掉的多核考试
这次考试真正能写出来的也就两道题,以下简单地记录一下。
随机产生2个10*10的浮点数矩阵A和B,先将矩阵A和B作转置,然后再相乘,请用windows 多线程函数方法和openMP方式分别编写实现上述运算的C语言并行实现程序,要求显示矩阵A和B,以及最终的运算结果。
题目涉及到矩阵转置和相乘两个主要内容,在编程时,我只对矩阵相乘进行openmp和多线程并行处理。
本题中,假设 A 、 B A、B A、B均为 N × N N\times N N×N矩阵,令 C = A B C=AB C=AB,则矩阵 C C C第 i i i行第 j j j列原始可表示为:
C i j = ∑ k = 1 N a i k b k j = a i 1 b 1 j + a i 2 b 2 j + ⋯ + a i N b N j C_{ij}=\sum_{k=1}^Na_{ik}b_{kj}=a_{i1}b_{1j}+a_{i2}b_{2j}+\cdots +a_{iN}b_{Nj} Cij=k=1∑Naikbkj=ai1b1j+ai2b2j+⋯+aiNbNj 所以为了计算 A A A、 B B B相乘结果,需要三层循环,最内层计算 C C C中单个元素的值,第二层计算 C C C中单行元素的值,最外层计算整个矩阵 C C C的值。为了减少线程开销,我们只对最外层循环进行并行处理,即每个线程计算一行相乘的结果。完整程序如下:
#include#include #include #include "omp.h"using namespace std;#define N 10 // 矩阵维数// 计算一行矩阵相乘结果的线程函数void func(const double* a, const double* b, double* result, int i){ // a:矩阵a的首地址 // b:矩阵b的首地址 // result:结果矩阵的第i行首地址 // i:待计算的行号 for (int j = 0; j < N; j++) { for (int k = 0; k < N; k++) { result[j] += a[i * N + k] * b[k * N + j]; } }}int main(){ double a[N][N] = { { 0} }; // 矩阵a double b[N][N] = { { 0} }; // 矩阵b double result_omp[N][N] = { { 0} }; // 保存openmp计算结果 double result_multithread[N][N] = { { 0} }; // 保存多线程计算结果 // 产生随机双精度矩阵 for (int i = 0; i < N; i++) { for (int j = 0; j < N; j++) { a[i][j] = (double)(rand() % 100) / 100; b[i][j] = (double)(rand() % 100) / 100; } } // 打印转置前的矩阵a、b cout << "----------------------------" << endl; cout << "转置前a" << endl; for (int i = 0; i < N; i++) { for (int j = 0; j < N; j++) { printf("%5.3lf ", a[i][j]); } cout << endl; } cout << "----------------------------" << endl; cout << "转置前b" << endl; for (int i = 0; i < N; i++) { for (int j = 0; j < N; j++) { printf("%5.3lf ", b[i][j]); } cout << endl; } //--------- 转置 --------- for (int i = 0; i < N; i++) { for (int j = i; j < N; j++) { double at = a[i][j]; double bt = b[i][j]; a[i][j] = a[j][i]; b[i][j] = b[j][i]; a[j][i] = at; b[j][i] = bt; } } // 打印转置后的矩阵a、b cout << "----------------------------" << endl; cout << "转置后a" << endl; for (int i = 0; i < N; i++) { for (int j = 0; j < N; j++) { printf("%5.3lf ", a[i][j]); } cout << endl; } cout << "----------------------------" << endl; cout << "转置后b" << endl; for (int i = 0; i < N; i++) { for (int j = 0; j < N; j++) { printf("%5.3lf ", b[i][j]); } cout << endl; } //--------- 矩阵相乘 --------- // OMP方法#pragma omp parallel for for (int i = 0; i < N; i++) { for (int j = 0; j < N; j++) { for (int k = 0; k < N; k++) result_omp[i][j] += a[i][k] * b[k][j]; } } // 多线程方法 double* aa = a[0]; // 指向矩阵a首地址的指针 double* bb = b[0]; // 指向矩阵b首地址的指针 thread t[N]; for (int i = 0; i < N; i++) { // 一个线程计算一行结果,共有N个线程 t[i] = thread(func, aa, bb, result_multithread[i], i); } // 等待线程结束 for (int i = 0; i < N; i++) { t[i].join(); } // 打印OMP计算结果 cout << "----------------------------" << endl; cout << "omp计算结果:" << endl; for (int i = 0; i < N; i++) { for (int j = 0; j < N; j++) { printf("%5.3lf ", result_omp[i][j]); } cout << endl; } // 打印多线程计算结果 cout << "----------------------------" << endl; cout << "multi thread计算结果:" << endl; for (int i = 0; i < N; i++) { for (int j = 0; j < N; j++) { printf("%5.3lf ", result_multithread[i][j]); } cout << endl; } return 0;}
运行结果如下:
某停车场有100个停车位,共有3个入口,2个出口。剩余车位数量需要实时提供给各个出入口。请设计一个管理程序,要求使用多线程编程,每进入或驶出一辆车,在屏幕上输出当前空余的车位,如果没有剩余车位了,就要限制车辆进入该停车场。
这道题我感觉做复杂了,用到了C++11里的条件变量和互斥锁,设置两个条件变量,一个用于判断是否能够进入停车场,另一个用于判断是否能驶出停车场。
#include#include #include #include using namespace std;// 停车场的最大车位数量#define PAKING_SPACE_MAX 100// 入口数量#define NUM_ENTER 3// 出口数量#define NUM_GO_OUT 2// 线程中的循环次数,此时设置为100次// 这样总共驶出次数为200次,进入次数为300次,最终停车场剩余车位应该为零#define FOR_NUM 100 int parkingspace = PAKING_SPACE_MAX; // 当前停车位数量mutex m;condition_variable cv1; // 进入操作的条件变量condition_variable cv2; // 驶出操作的条件变量// 车辆进入的线程函数void t_enter(void){ // 循环进入100辆车 for (int i = 0; i < FOR_NUM; i++) { unique_lock mylock(m); // 剩余车位数为0,表明停车场满了 if (parkingspace <= 0) cv1.wait(mylock); // 不允许车进入,让他们在外面等 parkingspace--; cout << "进入一辆车,剩余车位:" << parkingspace << endl; // 唤醒一个在等待中的线程,表示现在有车可以出去 cv2.notify_one(); // 延时100ms this_thread::sleep_for(chrono::milliseconds(100)); }}// 车辆驶出的线程函数void t_go_out(void){ // 循环驶出100辆车 for (int i = 0; i < FOR_NUM; i++) { unique_lock mylock(m); // 如果剩余车位数大于或者等于最大车位数量,则说明停车场是空的 if (parkingspace >= PAKING_SPACE_MAX) cv2.wait(mylock); // 此时没有车辆,阻塞这个驶出线程 parkingspace++; cout << "驶出一辆车,剩余车位:" << parkingspace << endl; // 唤醒一个在等待中的进入线程,表明有空车位,可以进入 cv1.notify_one(); // 延时100ms this_thread::sleep_for(chrono::milliseconds(100)); }}int main(){ thread t1[NUM_ENTER]; // 模拟三个入口 thread t2[NUM_GO_OUT]; // 模拟两个出口 /* 开启三个入口线程*/ for (int i = 0; i < NUM_ENTER; i++) { t1[i] = thread(t_enter); } /* 开启两个出口线程 */ for (int i = 0; i < NUM_GO_OUT; i++) { t2[i] = thread(t_go_out); } /* 等待所有入口线程执行完毕 */ for (int i = 0; i < NUM_ENTER; i++) { t1[i].join(); } /* 等待所有出口线程执行完毕 */ for (int i = 0; i < NUM_GO_OUT; i++) { t2[i].join(); }}
结果如下:
转载地址:http://umvgn.baihongyu.com/