使用Windows API 编写按行分配的计算矩阵向量相乘的并行程序
水了一学期的院选修,万万没想到期末考试还有比较硬核的编程题,居然还涉及到多线程了,而且是调用Windows接口函数写多线程。虽然学汇编的时候有所了解,但毕竟没尝试过,思来想去,写出了下面的蹩脚代码,不足之处还望各位批评指正。题目描述如下:
采用windows接口函数,编写一个计算矩阵向量相乘的并行程序,矩阵按行划分后分别散发到不同的线程中,向量被复制到各个线程中,程序执行结束时,由主线程输出结果向量。假设矩阵定义为浮点型数组A[64][64],向量定义为浮点型数组y[64],结果向量存放到浮点型数组z[64]中,所用处理器有8个计算核。
开始分析:如果把矩阵按行分配给不同线程的话,很明显每个线程应该被分配八行。由于对不同行的矩阵进行操作不会发生冲突,所以连线程的同步机制都用不到,就是简单的编写一个计算矩阵向量相乘的线程函数,然后创建多个线程执行就可以了。代码实现如下:
1 #include <windows.h> 2 #include <stdio.h> 3 4 double z[64]; //结果向量 5 double y[64]; //待乘向量 6 double A[64][64];//待乘矩阵 7 const int numThreads = 8;//线程数 8 9 DWORD WINAPI threadFunction(LPVOID pArg) { 10 int myNum = *((int *)pArg); //获取本线程所需参数 11 int n = myNum + 8; //设置外层循环上界 12 for(int i = myNum; i < n; ++i){//相乘计算的具体步骤 13 for(int j = 0; j < 64; ++j) 14 z[i] += A[i][j] * y[i]; 15 } 16 return 0; 17 } 18 19 int main() { 20 HANDLE threadHandles[numThreads];//线程数组 21 int tNum[numThreads];//用于传给线程的参数数组 22 23 printf("请输入矩阵:\n"); 24 for(int i = 0; i < 64; ++i) 25 for(int j = 0; j < 64; ++j) 26 scanf("%lf", &A[i][j]); 27 28 printf("请输入向量:\n"); 29 for(int i = 0; i < 64; ++i) 30 scanf("%lf", &y[i]); 31 32 printf("相乘后的结果向量为: \n"); 33 34 for(int i = 0; i < numThreads; ++i) { 35 tNum[i] = i * 8; //给传给线程的参数赋值 36 threadHandles[i] = CreateThread( NULL, // 安全属性 37 0, // 栈大小 38 threadFunction, // 传给线程的函数 39 (LPVOID)&tNum[i],// 传给线程的参数 40 0, // 线程创建后立即激活 41 NULL); // 新线程的id会被传给这个参数所在的变量 42 } 43 WaitForMultipleObjects( numThreads, // 等待的线程数 44 threadHandles, // 等待的线程数组 45 TRUE, // 等待所有信号量有效在往下执行 46 INFINITE); // 表示无穷等待 47 for(int i = 0; i < 64; ++i) //输出结果向量 48 printf("%.2lf ", z[i]); 49 return 0; 50 }
至此,已经解决问题了。还好题目要求不是特别难,也算是通过一段代码初步了解如何使用Windows接口函数编写多线程了。不得不说C语言确实强大,可惜我基础不扎实加上现在又忘得差不多了,写这段代码时居然想通过scanf("%f",&变量名)来输入double类型的值,迟迟得不到预期结果。我还以为是多线程惹的祸,得亏调试了一下才知道原来我连值都没有正确输进去,double类型的输入格式必须是%lf,输出的话%f和%lf均可,学到了学到了。只有犯错了才能学的更透彻啊😭