基于Pthreads并行实现通用矩阵乘法、数组求和及二次方程组求解
文章参考:高性能计算实验——基于Pthreads并行实现通用矩阵乘法、数组求和及二次方程组求解
文章目录
一.实验目的
//
二.实验过程
1.通过 Pthreads 实现通用矩阵乘法
(1)问题描述
(2)解决思路
为了提高局部性,我们先将B转置,然后将A的不同行分发给不同的线程进行计算即可。
(3)核心代码
将矩阵B转置
void TransMatrix() {
int *temp = (int*)malloc(sizeof(int) * N * K);
int i, j;
for (i = 0; i < K; ++i) {
for (j = 0; j < N; ++j) {
temp[i * N + j] = B[j * K + i];
}
}
free(B);
B = temp;
}
随机生成矩阵
void GenMatrix() {
int i, j;
A = (int*)malloc(sizeof(int) * M * N);
B = (int*)malloc(sizeof(int) * N * K);
C = (int*)malloc(sizeof(int) * M * K);
for (i = 0; i < M; ++i) {
for (j = 0; j < N; ++j)
A[i * N + j] = rand() % 10;
}
for (i = 0; i < N; ++i) {
for (j = 0; j < K; ++j)
B[i * K + j] = rand() % 10;
}
printf("矩阵A:\n");
for (int i = 0; i < M; ++i) {
for (int j = 0; j < N; ++j)
printf("%d ", A[i * N + j]);
printf("\n");
}
printf("矩阵B:\n");
for (int i = 0; i < N; ++i) {
for (int j = 0; j < K; ++j)
printf("%d ", B[i * K + j]);
printf("\n");
}
TransMatrix();
}
创建线程
pthread_t *thread_handles = (pthread_t*)malloc(tnum * sizeof(pthread_t));
for (int thread = 0; thread < tnum; ++thread) {
pthread_create(&thread_handles[thread], NULL, Work, (void*)thread);
}
for (int thread = 0; thread < tnum; ++thread) {
pthread_join(thread_handles[thread], NULL);
}
工作函数
void* Work(void *id) {
long tid = (long) id;
int i, j, g, temp;
int srow = tid * trows;
int erow = (tid + 1) * trows - 1;
if (erow >= M) erow = M - 1;
for (i = srow; i <= erow; ++i) {
for (j = 0; j < K; ++j) {
temp = 0;
for (g = 0; g < N; ++g)
temp += A[i * N + g] * B[j * N + g];
C[i * K + j] = temp;
}
}
}
(4)实验结果
2.基于 Pthreads 的数组求和
(1)问题描述
(2)解决思路
编写的程序应该能控制每个线程最多提取的数,每个线程在循环中一直完成计算,其中当前要计算的元素下标以及计算和需要用锁进行保护。
(3)核心代码
锁初始化
pthread_mutex_t mutex1 = PTHREAD_MUTEX_INITIALIZER;
pthread_mutex_t mutex2 = PTHREAD_MUTEX_INITIALIZER;
数组初始化
void GenArray() {
array = (int*)(malloc(sizeof(int) * size));
printf("数组array各元素值为:\n");
for (int i = 0; i < size; ++i) {
array[i] = rand() % 10;
printf("%d ", array[i]);
}
printf("\n");
}
工作函数
void* Add(void *id) {
int part_sum = 0;
int start = 0, end = 0;
while (1) {
pthread_mutex_lock(&mutex2);
start = index;
index += num;
pthread_mutex_unlock(&mutex2);
end = start + num;
if (end > size) end = size;
for (int i = start; i < end; ++i) {
part_sum += array[i];
}
if (end == size) break;
}
pthread_mutex_lock(&mutex1);
sum += part_sum;
pthread_mutex_unlock(&mutex1);
}
分配任务
for (int i = 0; i < tnum; ++i) {
if (pthread_create(&thread[i], NULL, Add, (void*)i));
}
for (int i = 0; i < tnum; ++i) {
pthread_join(thread[i], NULL);
}
(4)实验结果
3.Pthreads 求解二次方程组的根
(1)问题描述
编写一个多线程程序来求解二次方程组𝑎𝑥2 + 𝑏𝑥 + 𝑐 = 0的根,使用下面的公式
(2)解决思路
让不同的线程处理不同的计算,最后的计算需要等到前面计算完成后再进行(使用一个变量进行标记通知)。
(3)核心代码
初始化锁
pthread_mutex_t mutex1 = PTHREAD_MUTEX_INITIALIZER;
各部分计算,注意Extract需要等待flag为2
void* DoubleB(void *id) {
A = b * b;
pthread_mutex_lock(&mutex1);
flag +=1;
pthread_mutex_unlock(&mutex1);
}
void* FourAC(void *id) {
B = 4 * a * c;
pthread_mutex_lock(&mutex1);
flag +=1;
pthread_mutex_unlock(&mutex1);
}
void* Extract(void *id) {
while (flag < 2) { }
C = A - B;
if (C >= 0) {
solved = 1;
C = sqrt(C);
}
}
void* DoubleA(void *id) {
D = 2 * a;
}
分配工作及计算最后结果
pthread_create(&thread[0], NULL, DoubleB, (void*)0);
pthread_create(&thread[1], NULL, FourAC, (void*)1);
pthread_create(&thread[2], NULL, DoubleA, (void*)2);
pthread_create(&thread[3], NULL, Extract, (void*)3);
for (int i = 0; i < 4; ++i) {
pthread_join(thread[i], NULL);
}
if (solved) {
int x1 = (-b + C) / D;
int x2 = (-b - C) / D;
printf("x1 = %d, x2 = %d\n", x1, x2);
}
else {
printf("方程无解\n");
}
(4)实验结果
4.编程题:编写一个Pthreads多线程程序来实现基于monte-carlo方法的y=x^2阴影面积估算
(1)问题描述
(2)解决思路
将阴影部分及上门的空白部分分为不同的区间,在每一个区间随机取值判断是否落在阴影区间,最后统计所有落在阴影区间的数量除以总区间数量即为估算的阴影部分面积。
(3)核心代码
每个区间随机取值
void* cast (void* args)
{
int i;
float x,y;
int temp=0;
for(i=0; i< (intervals/tnum); i++){
x= (float)(rand() % 1001) * 0.001f;
y= (float)(rand() % 1001) * 0.001f;
if(y<x*x) temp++;
}
pthread_mutex_lock(&mutex);
sum += temp;
pthread_mutex_unlock(&mutex);
}
分配任务及计算面积
for (i=0;i<tnum;i++) {
pthread_create(&thread[i], NULL, cast, NULL);
}
for (i=0;i<tnum;i++) {
pthread_join(thread[i], NULL);
}
float shadow=(float) sum/(float) intervals;
printf("落在阴影部分区间数为:%d\n",sum);
printf("总区间数为:%d\n",intervals);
printf("阴影部分估算面积为:%f\n",shadow);
(4)实验结果
三.实验总结
//
源码
/**
* @file pthread_mult.c
* @author wasam
* @brief 利用pthread求矩阵乘积
* @date 2022-10-21
* @last_edit_time 2022-10-21 16:41:21
* @version 0.1
* @copyright Copyright (c) 2022
*/
#include <pthread.h>
#include <stdlib.h>
#include <stdio.h>
#include <sys/time.h>
int M, N, K;
int *A, *B, *C;
int trows;
void TransMatrix() {
int *temp = (int*)malloc(sizeof(int) * N * K);
int i, j;
for (i = 0; i < K; ++i) {
for (j = 0; j < N; ++j) {
temp[i * N + j] = B[j * K + i];
}
}
free(B);
B = temp;
}
void GenMatrix() {
int i, j;
A = (int*)malloc(sizeof(int) * M * N);
B = (int*)malloc(sizeof(int) * N * K);
C = (int*)malloc(sizeof(int) * M * K);
for (i = 0; i < M; ++i) {
for (j = 0; j < N; ++j)
A[i * N + j] = rand() % 10;
}
for (i = 0; i < N; ++i) {
for (j = 0; j < K; ++j)
B[i * K + j] = rand() % 10;
}
printf("矩阵A:\n");
for (int i = 0; i < M; ++i) {
for (int j = 0; j < N; ++j)
printf("%d ", A[i * N + j]);
printf("\n");
}
printf("矩阵B:\n");
for (int i = 0; i < N; ++i) {
for (int j = 0; j < K; ++j)
printf("%d ", B[i * K + j]);
printf("\n");
}
TransMatrix();
}
void* Work(void *id) {
long tid = (long) id;
int i, j, g, temp;
int srow = tid * trows;
int erow = (tid + 1) * trows - 1;
if (erow >= M) erow = M - 1;
for (i = srow; i <= erow; ++i) {
for (j = 0; j < K; ++j) {
temp = 0;
for (g = 0; g < N; ++g)
temp += A[i * N + g] * B[j * N + g];
C[i * K + j] = temp;
}
}
}
int main(int argc, char* argv[]) {
if (argc != 5) {
printf("参数数量不正确,请输入四个参数:M, N, K, tnum\n");
return -1;
}
M = strtol(argv[1], NULL, 10);
N = strtol(argv[2], NULL, 10);
K = strtol(argv[3], NULL, 10);
GenMatrix();
int tnum = strtol(argv[4], NULL, 10);
trows = M / tnum;
pthread_t *thread_handles = (pthread_t*)malloc(tnum * sizeof(pthread_t));
struct timeval start,end;
gettimeofday(&start, NULL );
for (int thread = 0; thread < tnum; ++thread) {
pthread_create(&thread_handles[thread], NULL, Work, (void*)thread);
}
for (int thread = 0; thread < tnum; ++thread) {
pthread_join(thread_handles[thread], NULL);
}
gettimeofday(&end, NULL );
printf("矩阵C:\n");
for (int i = 0; i < M; ++i) {
for (int j = 0; j < K; ++j)
printf("%d ", C[i * K + j]);
printf("\n");
}
long timeuse =1000000 * ( end.tv_sec - start.tv_sec ) + end.tv_usec - start.tv_usec;
printf("所用时间为=%f\n",timeuse /1000000.0);
return 0;
}
/**
* @file array_sum.c
* @author wasam
* @brief 利用pthread对数组求和
* @date 2022-10-21
* @last_edit_time 2022-10-21 16:40:26
* @version 0.1
* @copyright Copyright (c) 2022
*/
#include <stdlib.h>
#include <stdio.h>
#include <pthread.h>
#include <sys/time.h>
pthread_mutex_t mutex1 = PTHREAD_MUTEX_INITIALIZER;
pthread_mutex_t mutex2 = PTHREAD_MUTEX_INITIALIZER;
int *array;
int index, num, size = 1000, sum;
void* Add(void *id) {
int part_sum = 0;
int start = 0, end = 0;
while (1) {
pthread_mutex_lock(&mutex2);
start = index;
index += num;
pthread_mutex_unlock(&mutex2);
end = start + num;
if (end > size) end = size;
for (int i = start; i < end; ++i) {
part_sum += array[i];
}
if (end == size) break;
}
pthread_mutex_lock(&mutex1);
sum += part_sum;
pthread_mutex_unlock(&mutex1);
}
void GenArray() {
array = (int*)(malloc(sizeof(int) * size));
printf("数组array各元素值为:\n");
for (int i = 0; i < size; ++i) {
array[i] = rand() % 10;
printf("%d ", array[i]);
}
printf("\n");
}
int main(int argc, char* argv[]) {
if (argc != 3) {
printf("参数数量不正确,请输入两个参数:num, threads\n");
return -1;
}
GenArray();
num = strtol(argv[1], NULL, 10);
int tnum = strtol(argv[2], NULL, 10);
pthread_t thread[tnum];
struct timeval start,end;
gettimeofday(&start, NULL );
for (int i = 0; i < tnum; ++i) {
if (pthread_create(&thread[i], NULL, Add, (void*)i));
}
for (int i = 0; i < tnum; ++i) {
pthread_join(thread[i], NULL);
}
gettimeofday(&end, NULL );
printf("sum = %d\n", sum);
long timeuse =1000000 * ( end.tv_sec - start.tv_sec ) + end.tv_usec - start.tv_usec;
printf("所用时间为=%f\n",timeuse /1000000.0);
return 0;
}
/**
* @file double_equal.c
* @author wasam
* @brief 利用pthread计算一元二次方程根
* @date 2022-10-21
* @last_edit_time 2022-10-21 17:15:54
* @version 0.1
* @copyright Copyright (c) 2022
*/
#include <stdlib.h>
#include <stdio.h>
#include <pthread.h>
#include <math.h>
pthread_mutex_t mutex1 = PTHREAD_MUTEX_INITIALIZER;
int a, b, c;
int A, B, C, D;
int flag = 0, solved = 0;
void* DoubleB(void *id) {
A = b * b;
pthread_mutex_lock(&mutex1);
flag +=1;
pthread_mutex_unlock(&mutex1);
}
void* FourAC(void *id) {
B = 4 * a * c;
pthread_mutex_lock(&mutex1);
flag +=1;
pthread_mutex_unlock(&mutex1);
}
void* Extract(void *id) {
while (flag < 2) { }
C = A - B;
if (C >= 0) {
solved = 1;
C = sqrt(C);
}
}
void* DoubleA(void *id) {
D = 2 * a;
}
int main(int argc, char* argv[]) {
if (argc != 4) {
printf("参数数量不正确,请输入三个参数:a, b, c\n");
return -1;
}
a = strtol(argv[1], NULL, 10);
b = strtol(argv[2], NULL, 10);
c = strtol(argv[3], NULL, 10);
pthread_t thread[4];
pthread_create(&thread[0], NULL, DoubleB, (void*)0);
pthread_create(&thread[1], NULL, FourAC, (void*)1);
pthread_create(&thread[2], NULL, DoubleA, (void*)2);
pthread_create(&thread[3], NULL, Extract, (void*)3);
for (int i = 0; i < 4; ++i) {
pthread_join(thread[i], NULL);
}
if (solved) {
int x1 = (-b + C) / D;
int x2 = (-b - C) / D;
printf("x1 = %d, x2 = %d\n", x1, x2);
}
else {
printf("方程无解\n");
}
}
4,。
/**
* @file monte_carlo.c
* @author wasam
* @brief 使用pthread和monte-carlo方法计算面积
* @date 2022-10-21
* @last_edit_time 2022-10-21 17:19:27
* @version 0.1
* @copyright Copyright (c) 2022
*/
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <math.h>
int intervals = 10000;
int tnum;
int sum = 0;
pthread_mutex_t mutex=PTHREAD_MUTEX_INITIALIZER;
void* cast (void* args)
{
int i;
float x,y;
int temp=0;
for(i=0; i< (intervals/tnum); i++){
x= (float)(rand() % 1001) * 0.001f;
y= (float)(rand() % 1001) * 0.001f;
if(y<x*x) temp++;
}
pthread_mutex_lock(&mutex);
sum += temp;
pthread_mutex_unlock(&mutex);
}
int main(int argc, char *argv[]){
if (argc != 3) {
printf("参数数量不正确,请输入两个参数:intervals, tnum\n");
return -1;
}
intervals = strtol(argv[1], NULL, 10);
tnum = strtol(argv[2], NULL, 10);
pthread_t thread[tnum];
int i;
for (i=0;i<tnum;i++) {
pthread_create(&thread[i], NULL, cast, NULL);
}
for (i=0;i<tnum;i++) {
pthread_join(thread[i], NULL);
}
float shadow=(float) sum/(float) intervals;
printf("落在阴影部分区间数为:%d\n",sum);
printf("总区间数为:%d\n",intervals);
printf("阴影部分估算面积为:%f\n",shadow);
return 0;
}