Dynamic Matrix Multiplication with Pthreads - c

I'm a beginner with Thread Programming and C in general and I'm trying to figure out how to do a simple Matrix Multiplication with Pthreads. I want to create a thread for every column and put the results in a Result Matrix. I'm trying to do it dynamicly, which means the user is allowed to use an input as a size to create two n x n matrices.
My code right now, excluding filling the matrix and reading the size n is the following:
#include <pthread.h>
#include <stdio.h>
#include<stdlib.h>
typedef struct Matrix {
int line, col, size;
double (*MA)[];
double (*MB)[];
double (*MC)[];
} Matrix;
void *multiply(void *arg) {
Matrix* work = (Matrix*) arg;
int s, z;
s = work->col;
z = work->line;
work->MC[0][0] = 0.0.//can't use MC, MB, MA here!!
return 0;
}
int main() {
Matrix* m;
//read size and set it to int size (miissing here, does work)
double MA[size][size], MB[size][size], MC[size][size];
int i, j;
//filling the matrices (missing here, does work)
pthread_t threads[size];
for (i = 0; i < size; i++) {
m = malloc(sizeof(Matrix*));
m->size = size;
m->col = i;
pthread_create(&threads[i], NULL, multiply, m);
}
for (i = 0; i < size; i++) {
pthread_join(threads[i], NULL);
}
return 0;
}
The problem is, that I cant use neither MA, MB nor NC(:= the result) in the multiply method with something like its shown in the code.
I just get the error "invalid use of array with unspecific bounds" even though I declared all three of them in the main method.
Do I understand anything wrong here or how can I fix that? I tried to adapt a example of my lecture where a thread for every element will be created.
Thanks in advance!

Just about the error:
work->MC[0][0] = 0.0.//can't use MC, MB, MA here!!
MC was declared as double (*MC)[] and you try to use it as a two dimensional array like you had declared it double MC[N]{M]. You can use a two (or more) dimensional array like you did if and only if the first dimension was fixed or if you alloc it row by row.
So your program could be:
#include <pthread.h>
#include <stdio.h>
#include<stdlib.h>
typedef struct Matrix {
int line, col, size;
double MA[][];
double MB[][];
double MC[][];
} Matrix;
void *multiply(void *arg) {
Matrix* work = (Matrix*) arg;
int s, z;
s = work->col;
z = work->line;
work->MC[0][0] = 0.0
return 0;
}
int main() {
Matrix* m;
//read size and set it to int size (miissing here, does work)
double MA[][], MB[][], MC[][];
int i, j;
pthread_t threads[size];
MA = (double **) malloc(size * sizeof(double *));
MB = (double **) malloc(size * sizeof(double *));
MC = (double **) malloc(size * sizeof(double *));
for(int i=0;i<size;++i){
MA[i] = (double *) malloc(size * sizeof(double));
MB[i] = (double *) malloc(size * sizeof(double));
MC[i] = (double *) malloc(size * sizeof(double));
}
for (i = 0; i < size; i++) {
m = malloc(sizeof(Matrix*));
m->MA = MA;
m->MB = MB;
m->MC = MC;
m->size = size;
m->col = i;
pthread_create(&threads[i], NULL, multiply, m);
}
for (i = 0; i < size; i++) {
pthread_join(threads[i], NULL);
}
return 0;
}
But you must TAKE CARE that the thread can access to the data concurrently and so you should use some locks if different threads can use and change same values.

Related

How to send a matrix to a thread function?

I have to create in C a program that is able to calculate the determinant of a random 3x3 matrix using the Sarrus method. I have to use one thread (Thread A) to compute blue diagonals, and a second thread (Thread B) to compute red ones. (See img https://i.stack.imgur.com/HQL1U.png )
My code is:
#include <stdio.h>
#include <time.h>
#include <stdlib.h>
#include <pthread.h>
#include <unistd.h>
#define m 3
#define n 3
typedef struct thread_params{
int *data_matrix;
int diag_result;
} thread_params;
void *diagA (void *params){
thread_params *pp = (thread_params *) params;
int **matrix_ptr = &pp->data_matrix;
int diag = 0;
diag = matrix_ptr[0][0] * matrix_ptr[1][1] * matrix_ptr[2][2] + matrix_ptr[0][1] * matrix_ptr[1][2] * matrix_ptr[2][0] + matrix_ptr[0][2] * matrix_ptr[1][0] * matrix_ptr[2][1];
pp->diag_result = diag;
return (void *) &pp->diag_result;
}
void *diagB (void *params){
thread_params *pp = (thread_params *) params;
int **matrix_ptr = &pp->data_matrix;
int diag = 0;
diag = matrix_ptr[2][0] * matrix_ptr[1][1] * matrix_ptr[0][2] + matrix_ptr[2][1] * matrix_ptr[1][2] * matrix_ptr[0][0] + matrix_ptr[2][2] * matrix_ptr[1][0] * matrix_ptr[0][1];
pp->diag_result = diag;
return (void *) &pp->diag_result;
}
int main(){
// Create matrix
int **matrix;
int row;
matrix = (int **) malloc(m * sizeof(int *));
for (row = 0; row < m; row++){
matrix[row] = (int *) malloc(n * sizeof(int));
}
// Matrix initialization
srand(time(NULL));
for (int i = 0; i < m; i++){
for (int j = 0; j < n; j++){
matrix[i][j] = rand() % 10;
printf("%d ", matrix[i][j]);
}printf("\n");
}
// Thread creation
pthread_t threadA_id;
pthread_t threadB_id;
int *threadA_returnValue;
int *threadB_returnValue;
thread_params threadA_args;
thread_params threadB_args;
threadA_args.data_matrix = &matrix[0][0];
threadA_args.diag_result = 0;
threadB_args.data_matrix = &matrix[0][0];
threadB_args.diag_result = 0;
pthread_create(&threadA_id, NULL, &diagA, &threadA_args);
pthread_create(&threadB_id, NULL, &diagB, &threadB_args);
pthread_join(threadA_id, (void **) &threadA_returnValue);
pthread_join(threadB_id, (void **) &threadB_returnValue);
// Print results
printf("%d - %d = %d\n", *threadA_returnValue, *threadB_returnValue, *threadA_returnValue - *threadB_returnValue);
return 0;
}
The main problem is that I don't know how to correctly send the random matrix as argument to the threads functions. I tried to utilize a struct with a pointer inside but in this way I'm able to sent to the thread function only the first row of my matrix and then, when I try to access the second row, a segmentation fault error is generated.
I think my error is caused by this type of assignation:
threadA_args.data_matrix = &matrix[0][0];
How can I solve this problem?

initialize struct of C

typedef struct {
int num_rows;
int num_cols;
int** data;
} BinaryMatrix;
BinaryMatrix *ConstructBinaryMatrix(int num_rows, int num_cols) {
BinaryMatrix matrix = {
.num_rows = num_rows,
.num_cols = num_cols,
.data = (int **) malloc((num_rows) * sizeof(int *)),
};
int i;
for (i = 0; i < num_cols; i++) {
matrix.data[i] = (int *) malloc(num_cols * sizeof(int));
}
return &matrix;
}
Is this the correct way to define a BinaryMatrix, and how to initialize it?
Thanks for your help.
I got the following error.
BinaryMatrix* M;
M = ConstructBinaryMatrix(2, 2);
printf("%d:%d", M->num_rows, M->num_cols);
The output is: 4198012:0
You are returning a pointer to local data, which is bad form and doesn't work.
You should probably call malloc to allocate space for a BinaryMatrix structure, something like this:
BinaryMatrix *ConstructBinaryMatrix(int num_rows, int num_cols) {
BinaryMatrix *matrix = malloc(sizeof(BinaryMatrix));
matrix->num_rows = num_rows;
matrix->num_cols = num_cols,
matrix->data = malloc(num_rows * sizeof(int *));
int i;
for (i = 0; i < num_rows; i++) {
matrix->data[i] = malloc(num_cols * sizeof(int));
}
return matrix;
}
(Also I have fixed the loop bounds, as M.M. pointed out.)
i < num_cols should be i < num_rows.
Currently your code returns the address of a local variable. Local variables are destroyed when the function returns, so you in fact return a dangling pointer, not a good idea.
Instead you should return a copy of the local variable. Remove the * from the function prototype and from declaration of M, and remove the & from the return statement.
Unless its very large I would use:
#define M 3
#define N 3
int matrix[M][N]={{0,0,0},{0,0,0},{0,0,0}};
/* above possibly static */
Simples !
If the matrix was large simply use for loops to initialize.

Segmentation fault in int matrix

I was experimenting some basic C code that defines an int matrix with pointers.
typedef int **Matrix;
Matrix createMatrix(int lines, int columns) {
int i, j;
Matrix m = (Matrix) malloc(sizeof(int) * lines * columns);
for (i = 0; i < lines; ++i) {
for (j = 0; j < columns; ++j) {
m[i][j] = 0;
}
}
return m;
}
int main(int argc, char**argv) {
Matrix m = createMatrix(5, 10);
// ...
if (m[2][3] == 20) {
// ...
}
return 0;
}
However, these m[i][j] accesses are throwing segmentation faults. What's wrong here? Too many asterisks?
I was convinced that a pointer to a pointer to an int was effectively the same as a matrix.
Your allocation of the Matrix data item assumes you're accessing it linearly with a single index. If you want to access it with two indices, e.g., m[1][1] you need to allocate each dimension:
Matrix m = malloc(sizeof(int *) * lines);
for ( int i = 0; i < lines; i++ )
m[i] = malloc(sizeof(int) * columns);
Note also that you should not type cast malloc.

Returning 2d array from void function in C

I have a function that looks like this:
void swapRows(int row_1, int row_2, double **matrix, int n, int m)
{
double arrTemp = (double *)malloc(m * sizeof(double));
int i;
for(i = 0; i < m; i++)
{
arrTemp[i] = matrix[row_1][i];
*matrix[row_1][i] = matrix[row_2][i];
}
for(i = 0; i < m; i++)
{
*matrix[row_2][i] = arrTemp[i];
}
}
I tried dereferencing the array using two stars and a single star but can not figure it out. I don't want to store it in another array and return it VIA a double function, I need to return it from this void function. I am just swapping rows in the array and need to return the modified array to the main function.
As long as you´re only changing the values in the array, you don´t need to do anything special. Remove all * within the function and access the array like you don´t want to "return" it.
void swapRows(int row_1, int row_2, double **matrix, int n, int m){
double arrTemp = (double *)malloc(m * sizeof(double));
int i;
for(i = 0; i < m; i++){
arrTemp[i] = matrix[row_1][i];
matrix[row_1][i] = matrix[row_2][i]; //no *
}
for(i = 0; i < m; i++){
matrix[row_2][i] = arrTemp[i]; //no *
}
}
Unrelated problem, you´re missing a free to this malloc here.
And, as WhozCraig pointed out, in a double **matrix where each row is allocated separately, you could just switch the row pointers.
void swapRows(int row_1, int row_2, double **matrix, int n, int m){
double *tmp = matrix[row_1];
matrix[row_1] = matrix[row_2];
matrix[row_2] = tmp;
}

segmentation fault in 2D array assignment and thread call

I've wrote the following code to implement matrix multiplication but repeatedly i got segmentation fault error. It's seems to everything be OK. can anybody tell my what's the problem.
this is the code:
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
int matrixSize;
double ** a, ** b, ** c;
typedef struct tparms {
int row;
int col;
}tparms_t;
double ** allocateMatrix() {
int i;
double *vals, **temp;
//allocate values
vals = (double *) malloc (matrixSize * matrixSize * sizeof(double));
// allocate vector of pointers
temp = (double **) malloc (matrixSize * sizeof(double*));
for(i=0; i < matrixSize; i++)
temp[i] = &(vals[i * matrixSize]);
return temp;
}
void* multiply (void* _arg){
tparms_t * arg = (tparms_t *) _arg;
int i;
double sum;
for (i=0; i<matrixSize; i++)
sum += a[arg->row][i] * b[i][arg->col];
c[arg->row][arg->col] = sum;
}
void main(int argc, char *argv[]) {
pthread_t *threads;
if (argc != 2) {
printf("Usage: %s <size>, where size is dimension of square matrix\n", argv[0]);
exit(1);
}
int matrixSize = atoi(argv[1]);
threads = (pthread_t *) malloc(matrixSize * matrixSize * sizeof(pthread_t));
a = allocateMatrix();
b = allocateMatrix();
c = allocateMatrix();
int i, j;
for (i=0; i<matrixSize; i++){
for (j=0; j<matrixSize; j++){
a[i][j] = i + j;
b[i][j] = i + j;
}
}
for (i=0; i<matrixSize; i++){
for (j=0; j<matrixSize; j++){
tparms_t * tt = (tparms_t *)malloc(sizeof(tparms_t));
tt->row = i;
tt->col = j;
pthread_create(&threads[i*matrixSize + j], NULL, multiply, (void*)tt);
}
}
// two for for arrays
for (i=0; i<matrixSize; i++){
for (j=0; j<matrixSize; j++){
//do something ...
pthread_join(threads[i*matrixSize+j], NULL);
}
}
// end of two fors
}
there is a struct to pass data to threads, allocation function to allocate arrays and in main function i decide to create a thread for each of matrix elements. then a join function to wait until all threads do their job and create the c matrix elements.
You have int matrixSize = atoi (argv[1] );. Remove int because that creates another local instance of matrixSize.

Resources