Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Matrix Multiplication With Multiple Threads in C

Tags:

c

I want to create a C program that calculates the multiplication of two N*N matrices by using threads.
I started this code by referring to Matrix Multiplication using multiple threads but instead of creating N * N threads for each cell of the resulting matrix, I want to create N threads to do the multiplication concurrently where each row of the result matrix will be computed by a different thread.

My code looks like this so far:

#include <stdio.h>
#include <pthread.h>
#include <stdlib.h>
#include <string.h>

#define N 2

struct v {
    int i;  //Row
    int j;  //Column
};

int A[N][N] = {{ 1, 2 }, { 3, 4 }};//Matrix 1
int B[N][N] = {{ 2, 3 }, { 4, 5 }};//Matrix 2
int C[N][N];  //Resulting Matrix

static void *fnc(void *arg) {
    struct v *data = (struct v *)arg;
    int l;
    for (l = 0; l < N; l++) {
        int i = ((struct v *)data[l]).i;  //Row No
        int j = ((struct v *)data[l]).j;  //Column No
        int accumulator = 0;
        int d, sum = 0;
        for (d = 0; d < N; d++) {
            sum = sum + A[i][d] * B[d][j];
        }
        C[i][j] = sum;
        sum = 0;
    }
    return;
}

int main() {
    pthread_t threads[N];
    int i, k;
    for (i = 0; i < N; i++) {
        struct v *data[N];
        for (k = 0; k < N; k++) {
            data[k] = (struct v *)malloc(sizeof(struct v));
            data[k].i = i; //assign the row of C for thread to calculate
            data[k].j = k; //assign the column of C for thread to calculate
        }
        //In this example it creates 2 threads with passing data.
        //Data consists of row and column pairs for each thread, that will be calcuting the pairs.
        //Consider first iteration of this loop:
        //Thread 1 is created and data consists of (0,0) and (0,1) which are the targeted calculation cells for thread 1. 
        //In the second iteration: Thread 2 will have (1,0) and (1,1) pairs in its data.

        pthread_create(&threads[i], NULL, fnc, data);
    }
    for (i = 0; i < N; i++)
        pthread_join(threads[i], NULL);

   for (i = 0; i < N; i++)
      for (k = 0; k < N; k++)
        printf("%d\t", C[i][k]);

    return 0;
}

When I compile with

gcc thread.c -lpthread -lrt

I receive this Error:

thread.c: In function ‘fnc’:
thread.c:24:24: error: cannot convert to a pointer type
         int i=((struct v*)data[l]).i;//Row No
                        ^
thread.c:24:35: error: request for member ‘i’ in something not a structure or union
         int i=((struct v*)data[l]).i;//Row No
                                   ^
thread.c:25:24: error: cannot convert to a pointer type
         int j=((struct v*)data[l]).j;//Column No
                        ^
thread.c:25:35: error: request for member ‘j’ in something not a structure or union
         int j=((struct v*)data[l]).j;//Column No
                                   ^
thread.c: In function ‘main’:
thread.c:48:20: error: request for member ‘i’ in something not a structure or union
             data[k].i = i; //assign the row of C for thread to calculate
                    ^
thread.c:49:20: error: request for member ‘j’ in something not a structure or union
             data[k].j = k; //assign the column of C for thread to calculate

I believe the logic behind the code is correct and this sure looks like a simple argument passing problem. I put the whole code because I will be happy if I receive your comments about the problem and also a possible better solution for the desired job.

like image 920
Batuhan Tüter Avatar asked Oct 19 '15 22:10

Batuhan Tüter


2 Answers

Here it is a working solution was posted by @Michi. Your problem was that you were passing a pointer with the same address into a pthread_create also you had some issues with memory allocation. You had to allocate memory for two dimensional array, and pass into the pthread_create.

#include <stdio.h>
#include <pthread.h>
#include <stdlib.h>
#include <string.h>

#define N 3
#define n 3

struct v
{
    size_t i;
    size_t j;
};

double A[N][N] = {{1.0, 2.0, 4.0}, {3.0, 4.0, 5.0}, {4.0, 5.0, 7.0}};
double B[N][N] = {{2.0, 3.0, 9.0}, {4.0, 5.0, 7.0}, {2.0, 3.0, 9.0}};
double C[N][N];

static void * multiplication(void *arg){
    struct v *data = (struct v *)arg;

    size_t l;
    for(l=0; l < N; l++)
    {
        size_t i=(data[l]).i;
        size_t j=(data[l]).j;
        double sum=0;
        size_t d;

        for (d = 0; d < N; d++)
        {
            sum = sum + A[i][d]*B[d][j];
        }

        C[i][j] = sum;
        sum = 0;
    }
    return 0;
}

int main(void)
{
    pthread_t threads[n];
    size_t i, k;

    struct v **data;
    data = (struct v **)malloc(n * sizeof(struct v*));

    for(i = 0; i < n; i++)
    {
        data[i] = (struct v *)malloc(n * sizeof(struct v));

        for(k = 0; k < n; k++)
        {
            data[i][k].i = i;
            data[i][k].j = k;
        }

        pthread_create(&threads[i], NULL, multiplication, data[i]);
    }

    for(i = 0; i < n; i++)
    {
        pthread_join(threads[i], NULL);
    }

    for (i = 0; i < N; i++)
    {
        for (k = 0; k < N; k++)
        {
            printf("%lf\t", C[i][k]);
        }

        printf("\n");

        free(data[i]);
    }

    free(data);

    return 0;
}
like image 107
Mikhail Avatar answered Nov 21 '22 07:11

Mikhail


Hi i have implemented the 3*3 matrix multiplication using 3*3 thread.The code can be modified for N*N.The code is self explanatory.

*header*/
#include <pthread.h>
#include <stdio.h>
#include<stdlib.h>
/*macro*/
#define NUM_THREADS     9
/*I have defined the structure here to pass the multiple arguments 
when creating threads*/
/*structure declaration*/
struct thread_data
{
    int  element1[3];//passing the element of one matrix
    int  element2[3];//passing the element of other matrix
    int sum;//storing the result of multiplication
}thread_data_array[NUM_THREADS];
/**
 * @brief finds matrix multiplication function
 * param [in] : accepts the thread arguments
 *
 * @return void pointer
 */
void *multiplication(void *threadarg)
{
    int i;
    struct thread_data *my_data;
    my_data = (struct thread_data *) threadarg;/*type cast the 
void pointer to the struct thread*/
    //pointer
    my_data->sum=0;
    for(i=0;i<3;i++){/*multiply and add each element
of 1st matrix to 2nd matrix*/
        my_data->sum=my_data->sum
            +((my_data->element1[i])*(my_data->element2[i]));
    }
}
/*main*/
int main (int argc, char *argv[])
{
    pthread_t threads[NUM_THREADS];
    int rc;
    int t;
    int matrix_b[3][3]={{156,223,345},{456,5678,656},{712,811,922}};
//to store the matrix
    int matrix_a[3][3]={{123,278,335},{437,547,656},{734,832,944}};
    int ans[9];
    int i,j,count,z,k,l,q;
    t=i=j=z=count=k=q=l=0;
/*
suppose the matrices are
1 2 3       1 2 3
4 5 6       1 2 3
7 8 9       1 2 3
so to perform the multiplication
row 1 2 3 will be multiplied too column 
111 222 333 respectively.
so 123 shold be stored in 3 spreate threads 
and 111 222 333 should be stored in 3 seprate threads
123 111 should be in common thread
123 222 should be in common thread
123 333 should be in common thread
in this way below logic i have
writtten.
It is hard to understand at first glance..
so enjoy!!!!!!
*/
    while(z<3){
            for(count=0;count<3;count++){/*store the each row of
first matrix 3 times in 3 seprate threads*/
                for(j=0;j<3;j++)
                    thread_data_array[t].element1[j] 
                        = matrix_a[i][j];
                t++;
            }
/*store the each column of the second matrix in the spreate threads*/
            for(k=0;k<3;k++){
                for(l=0;l<3;l++)
                    thread_data_array[q].element2[l] 
                        = matrix_b[l][k];
                q++;
            }
            i++;
            z++;
    }
/*we have total 9 element in resultant matrix,so to create it we should
create 9 threads*/
    for(t=0; t<NUM_THREADS; t++){
        rc =pthread_create (&threads[t], NULL, multiplication,
                (void *) &thread_data_array[t]);
/*we are passing the function pointer and

the pointer to structure as the argument,since we want to pass multiple argumen
ts we                         are passing the structure poi
nter as the arguments.*/
        if (rc){//if rc is not 0,error is there
            printf("ERROR; return code from () is %d\n", rc);
            exit(-1);
        }
    }
/*
NAME         

       pthread_join - join with a terminated thread

SYNOPSIS         

       #include <pthread.h>

       int pthread_join(pthread_t thread_here, void **retval);

       Compile and link with -pthread.

DESCRIPTION         

   The pthread_join() function waits for the thread specified by thread_here
    to terminate.  If that thread has already terminated, then
    pthread_join() returns immediately.  The thread specified by thread
    must be joinable.
*/
    for (i = 0; i < 9; i++)/*to wait for all the threads to complete*/
            pthread_join(threads[i], NULL);
    printf("%d %d %d\n",thread_data_array[0].sum,thread_data_array[1].sum,thread_data_array[2].sum);
    printf("%d %d %d\n",thread_data_array[3].sum,thread_data_array[4].sum,thread_data_array[5].sum);
    printf("%d %d %d\n",thread_data_array[6].sum,thread_data_array[7].sum,thread_data_array[8].sum);
}
like image 44
jkd Avatar answered Nov 21 '22 08:11

jkd