dy9-spec
dy9-spec

Reputation: 23

matrix multiplication in a multithreading way

Hi Im trying to teach myself multithreading by working the following exercise: multiply two hardcoded matrixes, matrix1 and matrix2, and save the result in matrix3. The strategy is to assign one thread for the calculation of each element in the result matrix (matrix3).

Though the program is runnable, but the result is not right. Any enlightenments why the result is wrong? Thanks!

Code

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

#include "thread.h"

void *multiply(void *arguments);

#define X 2
#define Y 2
#define Z 3

int matrix1[X][Y] = {{0, 1}, {2, 3}};
int matrix2[Y][Z] = {{4, 5, 6}, {7, 8, 9}};
int matrix3[X][Z];

struct arguments_combo
{
    int rowIdxInMatrix1;
    int colIdxInMatrix2;
};

int main()
{
    thread_t threads[X * Z];

    for (int rowIdx = 0; rowIdx < X; rowIdx++)
    {
        for (int colIdx = 0; colIdx < Z; colIdx++)
        {
            struct arguments_combo arguments;
            arguments.rowIdxInMatrix1 = rowIdx;
            arguments.colIdxInMatrix2 = colIdx;
            pthread_create(&(threads[rowIdx * Z + colIdx]), NULL, multiply, (void *)&arguments);
        }
    }

    for (int rowIdx = 0; rowIdx < X; rowIdx++)
    {
        for (int colIdx = 0; colIdx < Z; colIdx++)
        {
            void *val_ptr;
            pthread_join(threads[rowIdx * Z + colIdx], &val_ptr);
            int *cur_val_ptr = (int *)val_ptr;
            printf("The rowIdx: %d and colIdx: %d and the val: %d\n", rowIdx, colIdx, *cur_val_ptr);
            matrix3[rowIdx][colIdx] = *cur_val_ptr;
            free(cur_val_ptr);
        }
    }

    return 0;
}

void *multiply(void *arguments)
{
    struct arguments_combo *data_ptr = (struct arguments_combo *)arguments;

    int rowIdxInMatrix1 = data_ptr->rowIdxInMatrix1;
    int colIdxInMatrix2 = data_ptr->colIdxInMatrix2;
    int *sum = malloc(sizeof(int));

    for (int i = 0; i < Y; i++)
    {
        *sum += matrix1[rowIdxInMatrix1][i] * matrix2[i][colIdxInMatrix2];
    }

    pthread_exit((void *)sum);
    return NULL;
}

Output

The rowIdx: 0 and colIdx: 0 and the val: 9
The rowIdx: 0 and colIdx: 1 and the val: 29
The rowIdx: 0 and colIdx: 2 and the val: 29
The rowIdx: 1 and colIdx: 0 and the val: 34
The rowIdx: 1 and colIdx: 1 and the val: 39
The rowIdx: 1 and colIdx: 2 and the val: 39

Upvotes: 2

Views: 72

Answers (1)

Eraklon
Eraklon

Reputation: 4288

Well I am not an expert of this subject just tried to correct it. Seems like the cause is this part

struct arguments_combo arguments;
arguments.rowIdxInMatrix1 = rowIdx;
arguments.colIdxInMatrix2 = colIdx;
pthread_create(&(threads[rowIdx * Z + colIdx]), NULL, multiply, (void *)&arguments);

Could be wrong, but I think there is a race condition here. You gave this single arguments variable address to all thread, but you also overwrite it later on so when a thread accessing it likely having some other value already.

If you create an args array like this struct arguments_combo args[X * Z]; at global scope and you change your code also to this:

args[rowIdx * Z + colIdx].rowIdxInMatrix1 = rowIdx;
args[rowIdx * Z + colIdx].colIdxInMatrix2 = colIdx;
pthread_create(&(threads[rowIdx * Z + colIdx]), NULL, multiply, (void *)&args[rowIdx * Z + colIdx]);

Then the result seems valid in this case

The rowIdx: 0 and colIdx: 0 and the val: 7
The rowIdx: 0 and colIdx: 1 and the val: 8
The rowIdx: 0 and colIdx: 2 and the val: 9
The rowIdx: 1 and colIdx: 0 and the val: 29
The rowIdx: 1 and colIdx: 1 and the val: 34
The rowIdx: 1 and colIdx: 2 and the val: 39

Although sometimes it will give still random values. The reason is that you do not initialize *sum to 0 in multiply function so don't forget to do it also and than everything seems to be working fine.

Upvotes: 1

Related Questions