Reputation: 23
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
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