基于Pthreads并行实现通用矩阵乘法、数组求和及二次方程组求解

基于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;
}
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
好的,下面给您介绍一下使用Pthreads实现矩阵向量乘法的方法: 首先,我们需要定义一个结构体,用于传递参数: ``` typedef struct { double *matrix; // 矩阵 double *vector; // 向量 double *result; // 结果 int rows; // 矩阵的行数 int cols; // 矩阵的列数 int start; // 起始行 int end; // 结束行 } thread_param_t; ``` 然后,我们需要编写一个线程函数,用于计算矩阵向量乘法: ``` void *multiply(void *arg) { thread_param_t *param = (thread_param_t *)arg; for (int i = param->start; i < param->end; i++) { double sum = 0.0; for (int j = 0; j < param->cols; j++) { sum += param->matrix[i * param->cols + j] * param->vector[j]; } param->result[i] = sum; } pthread_exit(NULL); } ``` 接下来,我们需要创建线程,并将参数传递给它们: ``` void multiply_matrix_vector(double *matrix, double *vector, double *result, int rows, int cols, int num_threads) { pthread_t threads[num_threads]; thread_param_t params[num_threads]; int rows_per_thread = rows / num_threads; for (int i = 0; i < num_threads; i++) { params[i].matrix = matrix; params[i].vector = vector; params[i].result = result; params[i].rows = rows; params[i].cols = cols; params[i].start = i * rows_per_thread; params[i].end = (i == num_threads - 1) ? rows : (i + 1) * rows_per_thread; pthread_create(&threads[i], NULL, multiply, (void *)&params[i]); } for (int i = 0; i < num_threads; i++) { pthread_join(threads[i], NULL); } } ``` 最后,我们可以调用 multiply_matrix_vector() 函数来进行矩阵向量乘法计算: ``` int main() { double matrix[4][3] = {{1.0, 2.0, 3.0}, {4.0, 5.0, 6.0}, {7.0, 8.0, 9.0}, {10.0, 11.0, 12.0}}; double vector[3] = {1.0, 2.0, 3.0}; double result[4] = {0.0}; multiply_matrix_vector((double *)matrix, vector, result, 4, 3, 2); for (int i = 0; i < 4; i++) { printf("%lf ", result[i]); } printf("\n"); return 0; } ``` 以上就是使用 Pthreads 实现矩阵向量乘法的方法,希望对您有所帮助!

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值