3 * gcc matrixmul.c -o matrixmul -lpthread -Wall -W -Wextra -ansi -pedantic
10 typedef struct matrix
{
16 typedef struct matrix_index
{
27 matrix_t
*mat1
, *mat2
, *mat3
;
29 /* Function prototypes */
30 mmret_t
matrix_alloc(matrix_t
**mat
, size_t rows
, size_t cols
);
31 void matrix_free(matrix_t
**mat
);
32 mmret_t
matrix_read(const char *path
, matrix_t
**mat
);
33 void matrix_print(const matrix_t
*mat
);
34 void *mulvect(void *arg
);
35 void diep(const char *s
);
37 int main(int argc
, char *argv
[])
41 size_t i
, j
, k
, mdepth
, numthreads
;
43 /* Check argument count */
45 fprintf(stderr
, "Usage: %s matfile1 matfile2\n", argv
[0]);
50 * Initialize `mdepth' variable
52 * We increase `mdepth' every time we succesfully call malloc().
53 * That way we can keep track of the "allocation depth" and easily
54 * free the memory whenever needed, e.g. if a fatal error occurs.
58 /* Read matrix data from files */
59 if (matrix_read(argv
[1], &mat1
) != MM_OK
)
60 goto CLEANUP_AND_EXIT
;
63 if (matrix_read(argv
[2], &mat2
) != MM_OK
)
64 goto CLEANUP_AND_EXIT
;
67 /* Is the multiplication feasible by definition? */
68 if (mat1
->cols
!= mat2
->rows
) {
69 fprintf(stderr
, "Matrices' dimensions size must satisfy (NxM)(MxK)=(NxK)\n");
70 goto CLEANUP_AND_EXIT
;
73 /* Allocate memory for the result */
74 if (matrix_alloc(&mat3
, mat1
->rows
, mat2
->cols
) != MM_OK
)
75 goto CLEANUP_AND_EXIT
;
78 /* How many threads do we need ? */
79 numthreads
= mat1
->rows
* mat2
->cols
;
81 /* v[k] holds the (i, j) pair in the k-th computation */
82 if ((v
= malloc(numthreads
* sizeof *v
)) == NULL
) {
84 goto CLEANUP_AND_EXIT
;
88 /* Allocate memory for the threads' ids */
89 if ((tid
= malloc(numthreads
* sizeof *tid
)) == NULL
) {
91 goto CLEANUP_AND_EXIT
;
95 /* Create the threads */
96 for (i
= 0; i
< mat1
->rows
; i
++) {
97 for (j
= 0; j
< mat2
->cols
; j
++) {
101 if (pthread_create(&tid
[k
], NULL
, mulvect
, (void *)&v
[k
])) {
102 perror("pthread_create");
103 goto CLEANUP_AND_EXIT
;
108 /* Make sure all threads are done */
109 for (i
= 0; i
< numthreads
; i
++)
110 if (pthread_join(tid
[i
], NULL
)) {
111 perror("pthread_join");
112 goto CLEANUP_AND_EXIT
;
115 /* Print the result */
122 case 3: matrix_free(&mat3
);
123 case 2: matrix_free(&mat2
);
124 case 1: matrix_free(&mat1
);
125 case 0: ; /* free nothing */
131 mmret_t
matrix_alloc(matrix_t
**mat
, size_t rows
, size_t cols
)
133 size_t i
, j
, mdepth
= 0;
135 *mat
= malloc(sizeof **mat
);
137 goto CLEANUP_AND_RETURN
;
143 (*mat
)->data
= malloc(rows
* sizeof(int *));
144 if ((*mat
)->data
== NULL
)
145 goto CLEANUP_AND_RETURN
;
148 for (i
= 0; i
< rows
; i
++) {
149 (*mat
)->data
[i
] = malloc(cols
* sizeof(int));
150 if ((*mat
)->data
[i
] == NULL
) {
153 goto CLEANUP_AND_RETURN
;
162 case 3: for (j
= 0; j
< i
; j
++) free((*mat
)->data
[j
]);
163 case 2: free((*mat
)->data
);
165 case 0: ; /* free nothing */
171 void matrix_free(matrix_t
**mat
)
175 for (i
= 0; i
< (*mat
)->rows
; i
++)
176 free((*mat
)->data
[i
]);
182 mmret_t
matrix_read(const char *path
, matrix_t
**mat
)
185 size_t i
, j
, rows
, cols
;
188 if ((fp
= fopen(path
, "r")) == NULL
) {
189 fprintf(stderr
, "Error opening file: %s\n", path
);
193 /* Read matrix dimensions */
194 fscanf(fp
, "%u%u", &rows
, &cols
);
196 /* Allocate memory for matrix */
197 if (matrix_alloc(mat
, rows
, cols
) == MM_ENOMEM
) {
202 /* Read matrix elements */
203 for (i
= 0; i
< (*mat
)->rows
; i
++) {
204 for (j
= 0; j
< (*mat
)->cols
; j
++) {
205 fscanf(fp
, "%d", &(*mat
)->data
[i
][j
]);
215 void matrix_print(const matrix_t
*mat
)
219 for (i
= 0; i
< mat
->rows
; i
++) {
220 for (j
= 0; j
< mat
->cols
; j
++) {
221 printf("%d ", mat
->data
[i
][j
]);
228 void *mulvect(void *arg
)
232 row
= *((int *)arg
+ 0);
233 col
= *((int *)arg
+ 1);
235 mat3
->data
[row
][col
] = 0;
236 for (i
= 0; i
< mat1
->cols
; i
++)
237 mat3
->data
[row
][col
] += mat1
->data
[row
][i
] * mat2
->data
[i
][col
];
242 void diep(const char *s
)