首页 > 解决方案 > 坚持使用 pthreads 进行矩阵乘法

问题描述

我目前正在尝试完成一个使用 pthreads 来加速矩阵乘法的分配。这个想法是让每个 pthread 都在大块行上工作

例如:1000 行和 4 个线程将是线程 0:行 0-249,线程 1:250-499,线程 2:500-749 和线程 3:750-999

  blocksOfWork = (BLOCK *) malloc(numberOfThreads*sizeof(BLOCK));

  for(i=0; i < numberOfThreads; i++){
    blocksOfWork[i].threadId = i;
    blocksOfWork[i].start_row = i * rows/numberOfThreads;
    if (i == numberOfThreads -1){
      blocksOfWork[i].end_row = rows - 1;
    }
    else{
      blocksOfWork[i].end_row = (i+1)*rows/numberOfThreads -1;
    }
    blocksOfWork[i].start_col = 0;
    blocksOfWork[i].end_col = columns -1;
  }

我只是很难理解如何执行矩阵乘法迭代,我已经为调试目的放置了一个打印语句,但我仍然无法弄清楚,ThreadMMulti Function。任何正确方向的有用提示将不胜感激。这是完整的代码

/*Program to generate two square 2D arrays of random doubles and
   time their multiplication.
   Program utlizies pthreads to efficiently perform matrix Multiplication
   Compile by: gcc -o mmult -O3 mmultHW6.c -lpthread
   Run by:  ./mmult 1000 1000 2
 */

#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <math.h>
#include <pthread.h>

#define TRUE 1
#define FALSE 0
#define BOOL int

typedef struct {
  int threadId;
  int start_row;
  int end_row;
  int start_col;
  int end_col;
} BLOCK;


// function prototypes
double ** allocate2DArray(int rows, int columns);
void print2DArray(int rows, int columns, double ** array2D);
void generateRandom2DArray(int rows, int columns,
               double min, double max, double ** random2DArray);
BOOL equal2DArrays(int rows, int columns, double ** array1, double ** array2,
           double tolerance);
void matrixMultiplication(int rows1, int columns1, double ** array1,
              int rows2, int columns2, double ** array2,
              double ** product);
void matrixMultiplicationAlt(int rows1, int columns1, double ** array1,
                 int rows2, int columns2, double ** array2,
                 double ** product);
void * threadMMult(void * rank);

int numberOfThreads;
double ** A;
double ** B;
double ** C;
double ** C_alt;

int rows, columns;

int main(int argc, char ** argv) {


  long i, startTime, endTime,seqTime, paralellTime;
  BLOCK * blocksOfWork;
  int errorCode;
  double tolerence;
  pthread_t * threadHandles;
  if (argc !=3) {
    printf("Usage: %s <# of rows><# of columns><# of Threads>\n", argv[0]);
    exit(-1);
  } // end if

  sscanf(argv[1], "%d", &rows);
  sscanf(argv[1], "%d", &numberOfThreads);
  columns = rows;


  // seed the random number generator
  srand( time(NULL) );

  A = allocate2DArray(rows, columns);
  B = allocate2DArray(rows, columns);
  C = allocate2DArray(rows, columns);
  C_alt = allocate2DArray(rows, columns);
  generateRandom2DArray(rows, columns, -1.0, +1.0, A);
  generateRandom2DArray(rows, columns, -1.0, +1.0, B);

  printf("after initializing matrices\n");

  time(&startTime);

  matrixMultiplicationAlt(rows, columns, A, rows, columns, B, C_alt);

  time(&endTime);

  seqTime = endTime-startTime;
  printf("Matrix Multiplication Alt. time = %ld\n",seqTime);


  time(&startTime);

  threadHandles = (pthread_t *)
  malloc(numberOfThreads*sizeof(pthread_t));
  blocksOfWork = (BLOCK *) malloc(numberOfThreads*sizeof(BLOCK));

  for(i=0; i < numberOfThreads; i++){
    blocksOfWork[i].threadId = i;
    blocksOfWork[i].start_row = i * rows/numberOfThreads;
    if (i == numberOfThreads -1){
      blocksOfWork[i].end_row = rows - 1;
    }
    else{
      blocksOfWork[i].end_row = (i+1)*rows/numberOfThreads -1;
    }
    blocksOfWork[i].start_col = 0;
    blocksOfWork[i].end_col = columns -1;
  }
  for (i=0; i < numberOfThreads; i++) {
    if (errorCode = pthread_create(&threadHandles[i], NULL, threadMMult,
                   &blocksOfWork[i]) != 0) {
      printf("pthread %d failed to be created with error code %d\n", i, errorCode);
    } // end if
  } // end for

  for (i=0; i < numberOfThreads; i++) {
    if (errorCode = pthread_join(threadHandles[i], (void **) NULL) != 0) {
      printf("pthread %d failed to be joined with error code %d\n", i, errorCode);
    } // end if
  } // end for

  time(&endTime);
  paralellTime = endTime-startTime;
  printf("Parallel Matrix Multiplication time = %ld\n",paralellTime);


  if (equal2DArrays(rows, columns, C, C_alt, 0.000001)) {
    printf("Arrays match with tolerance of %.000001f\n", 0.000001);
  } else {
    printf("Arrays DON'T match with tolerance of %.000001f\n", 0.000001);
  } // end if

  return 0;

} // end main



void * threadMMult(void * arg){
  BLOCK * block = (BLOCK *) arg;
  int threadId = block->threadId;
  int startRow = block->start_row;
  int endRow = block->end_row;
  int startCol = block->start_col;
  int endCol = block->end_col;
  int i, j, k, sum;

  for (int i=startRow; i<=endRow;i++){
    for (int j = startCol; j<=endCol; j++){
      //C[i][j] = 0;
      for(int k=0; k<= columns-1; k++){
      //C[i][j] += A[i][k]*B[k][j];
        printf("%lu - C[%d][%d] += A[%d][%d]*B[%d][%d]\n", pthread_self()
        , i,j,i,k,k,j);
      }

    }
  }

}

/*******************************************************************
 * Function matrixMultiplicationAlt passed two matrices and returns
 * their product.
 ********************************************************************/
void matrixMultiplicationAlt(int rows1, int columns1, double ** array1,
                 int rows2, int columns2, double ** array2,
                 double ** product) {
  int i, j, k;
  double ** array2_transpose;

  if (columns1 != rows2) {
    printf("Matrices cannot be multiplied -- incompatible dimensions!\n");
    exit(-1);
  } // end if

  // Transposes array2
  array2_transpose = allocate2DArray(columns2, rows2);
  for (i=0; i < rows2; i++) {
    for (j=0; j < columns2; j++) {
      array2_transpose[j][i] = array2[i][j];
    } /* end for (j */
  } /* end for (i */

  // Matrix Multiplication uses array1 and array2_transpose
  for (i=0; i < rows1; i++) {
    for (j=0; j < columns2; j++) {
      product[i][j] = 0.0;
      for (k=0; k < columns1; k++) {
        product[i][j] += array1[i][k]*array2_transpose[j][k];
      } /* end for (k */
    } /* end for (j */
  } /* end for (i */

} // end matrixMultiplicationAlt



/*******************************************************************
 * Function allocate2DArray dynamically allocates a 2D array of
 * size rows x columns, and returns it.
 ********************************************************************/
double ** allocate2DArray(int rows, int columns) {
  double ** local2DArray;
  int r;

  local2DArray = (double **) malloc(sizeof(double *)*rows);

  for (r=0; r < rows; r++) {
    local2DArray[r] = (double *) malloc(sizeof(double)*columns);
  } // end for

  return local2DArray;
} // end allocate2DArray


/*******************************************************************
 * Function generateRandom2DArray is passed the # rows, the # columns,
 * min. value, max. value, and returns random2DArray containing
 * randomly generated doubles.
 ********************************************************************/
void generateRandom2DArray(int rows, int columns,
               double min, double max, double ** random2DArray) {
  int r, c;
  double range, div;

  for (r = 0; r < rows; r++) {
    for (c = 0; c < columns; c++) {
      range = max - min;
      div = RAND_MAX / range;
      random2DArray[r][c] = min + (rand() / div);
    } // end for (c...
  } // end for (r...
} // end generateRandom2DArray


/*******************************************************************
 * Function print2DArray is passed the # rows, # columns, and the
 * array2D.  It prints the 2D array to the screen.
 ********************************************************************/
void print2DArray(int rows, int columns, double ** array2D) {
  int r, c;
  for(r = 0; r < rows; r++) {
    for (c = 0; c < columns; c++) {
      printf("%10.5lf", array2D[r][c]);
    } // end for (c...
    printf("\n");
  } // end for(r...

} // end print2DArray



/*******************************************************************
 * Function equal2DArrays is passed the # rows, # columns, two
 * array2Ds, and tolerance.  It returns TRUE if corresponding array
 * elements are equal within the specified tolerance; otherwise it
 * returns FALSE.
 ********************************************************************/
BOOL equal2DArrays(int rows, int columns, double ** array1, double ** array2,
           double tolerance) {

  int r, c;

  for(r = 0; r < rows; r++) {
    for (c = 0; c < columns; c++) {
      if (fabs(array1[r][c] - array2[r][c]) > tolerance) {
        return FALSE;
      } // end if
    } // end for (c...
  } // end for(r...
  return TRUE;

} // end equal2DArray

标签: cpthreads

解决方案


推荐阅读