-
-
Save KyroChi/6820ba6be6b652ff166bc0a08b12cb6f to your computer and use it in GitHub Desktop.
Medium multithreading post: Multithreaded full version
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <stdio.h> | |
#include <stdlib.h> | |
#include <pthread.h> | |
#include <time.h> | |
typedef struct { | |
unsigned int n_rows; | |
unsigned int n_cols; | |
double* data; | |
} matrix; | |
matrix* | |
new_matrix (unsigned int n_rows, unsigned int n_cols) | |
{ | |
matrix* mat = malloc( sizeof(mat) ); | |
if ( !mat ) { | |
printf("Failed to malloc\n"); | |
exit(1); | |
} | |
mat->n_rows = n_rows; | |
mat->n_cols = n_cols; | |
mat->data = calloc( n_rows * n_cols, sizeof(double) ); | |
return mat; | |
} | |
void | |
free_matrix (matrix* A) | |
{ | |
free(A->data); | |
free(A); | |
return; | |
} | |
unsigned int | |
get_index (matrix* A, unsigned int r, unsigned int c) | |
{ | |
return A->n_cols * r + c; | |
} | |
void | |
set_matrix (matrix* A, unsigned int r, unsigned int c, unsigned int v) | |
{ | |
unsigned int ind = get_index(A, r, c); | |
A->data[ind] = v; | |
return; | |
} | |
double | |
get_matrix (matrix* A, unsigned int r, unsigned int c) | |
{ | |
unsigned int ind = get_index(A, r, c); | |
return A->data[ind]; | |
} | |
double | |
matmul_subroutine (matrix* A, unsigned int row, | |
matrix* B, unsigned int col) | |
{ | |
double sum = 0; | |
unsigned int ii; | |
for ( ii = 0; ii < A->n_cols; ii++ ) { | |
sum += get_matrix(A, row, ii) | |
* get_matrix(B, ii, col); | |
} | |
return sum; | |
} | |
matrix* | |
matmul (matrix* A, matrix* B) | |
{ | |
matrix* AB = new_matrix(A->n_rows, B->n_cols); | |
double ab; | |
unsigned int ii, jj; | |
for ( ii = 0; ii < A->n_rows; ii++ ) { | |
for ( jj = 0; jj < B->n_cols; jj++ ) { | |
ab = matmul_subroutine(A, ii, B, jj); | |
set_matrix(AB, ii, jj, ab); | |
} | |
} | |
return AB; | |
} | |
void | |
print_matrixf (Matrix2D* A, unsigned int precision) | |
{ | |
double num = 0; | |
printf("["); | |
unsigned int ii, jj; | |
for (ii = 0; ii < A->n_rows; ii += 1) { | |
if (ii == 0) { | |
printf("[ "); | |
} else { | |
printf(" [ "); | |
} | |
for (jj = 0; jj < A->n_cols - 1; jj += 1) { | |
num = index_matrix_2D(A, ii, jj); | |
printf("%.*f \t", precision, num); | |
} | |
num = index_matrix_2D(A, ii, jj); | |
printf("%.*f", precision, num); | |
if (ii < A->n_rows - 1) { | |
printf(" ],\n"); | |
} | |
} | |
printf(" ]]\n"); | |
return; | |
} | |
typedef struct { | |
matrix* A; | |
unsigned int row; | |
matrix* B; | |
unsigned int col; | |
matrix* AB; | |
} thread_params; | |
void* | |
matmul_subroutine_thread (void* params) | |
{ | |
thread_params* t_params = (thread_params*) params; | |
double a = matmul_subroutine(t_params->A, | |
t_params->row, | |
t_params->B, | |
t_params->col); | |
set_matrix(t_params->AB, t_params->row, t_params->col, a); | |
return NULL; | |
} | |
matrix* | |
matmul_threaded (matrix* A, matrix*B) | |
{ | |
matrix* AB = new_matrix(A->n_rows, B->n_cols); | |
double ab; | |
pthread_t* tids = malloc( sizeof(pthread_t) | |
* A->n_rows * B->n_cols); | |
thread_params** params = malloc( sizeof(thread_params*) | |
* A->n_rows * B->n_cols); | |
thread_params* args; | |
unsigned int ii, jj, ind; | |
for ( ii = 0; ii < A->n_rows; ii++ ) { | |
for ( jj = 0; jj < B->n_cols; jj++ ) { | |
ind = ii * B->n_cols + jj; | |
args = params[ind]; | |
args = malloc( sizeof(thread_params) ); | |
args->A = A; | |
args->row = ii; | |
args->B = B; | |
args->col = jj; | |
args->AB = AB; | |
pthread_create(&tids[ind], NULL, | |
&matmul_subroutine_thread, | |
args); | |
} | |
} | |
for ( ii = 0; ii < A->n_rows * B->n_cols; ii++ ) { | |
pthread_join(tids[ii], NULL); | |
} | |
return AB; | |
} | |
int | |
main (void) | |
{ | |
struct timespec start, finish; | |
double elapsed; | |
unsigned int a_rows = 10; | |
unsigned int a_cols = 100; | |
unsigned int b_cols = 10; | |
matrix* A = new_matrix(a_rows, a_cols); | |
matrix* B = new_matrix(a_cols, b_cols); | |
clock_gettime(CLOCK_MONOTONIC, &start); | |
matrix* AB = matmul(A, B); | |
clock_gettime(CLOCK_MONOTONIC, &finish); | |
elapsed = (finish.tv_sec - start.tv_sec); | |
elapsed += (finish.tv_nsec - start.tv_nsec) / 1000000000.0; | |
printf("Linear took \t%.8f seconds\n", elapsed); | |
clock_gettime(CLOCK_MONOTONIC, &start); | |
AB = matmul_threaded(A, B); | |
clock_gettime(CLOCK_MONOTONIC, &finish); | |
elapsed = (finish.tv_sec - start.tv_sec); | |
elapsed += (finish.tv_nsec - start.tv_nsec) / 1000000000.0; | |
printf("Parallel took \t%.8f seconds\n", elapsed); | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment