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"
70 "(NxM)(MxK)=(NxK)\n");
71 goto CLEANUP_AND_EXIT
;
74 /* Allocate memory for the result */
75 if (matrix_alloc(&mat3
, mat1
->rows
, mat2
->cols
) != MM_OK
)
76 goto CLEANUP_AND_EXIT
;
79 /* How many threads do we need ? */
80 numthreads
= mat1
->rows
* mat2
->cols
;
82 /* v[k] holds the (i, j) pair in the k-th computation */
83 if ((v
= malloc(numthreads
* sizeof *v
)) == NULL
) {
85 goto CLEANUP_AND_EXIT
;
89 /* Allocate memory for the threads' ids */
90 if ((tid
= malloc(numthreads
* sizeof *tid
)) == NULL
) {
92 goto CLEANUP_AND_EXIT
;
96 /* Create the threads */
97 for (i
= 0; i
< mat1
->rows
; i
++) {
98 for (j
= 0; j
< mat2
->cols
; j
++) {
102 if (pthread_create(&tid
[k
], NULL
, mulvect
, (void *)&v
[k
])) {
103 perror("pthread_create()");
104 goto CLEANUP_AND_EXIT
;
109 /* Make sure all threads are done */
110 for (i
= 0; i
< numthreads
; i
++)
111 if (pthread_join(tid
[i
], NULL
)) {
112 perror("pthread_join()");
113 goto CLEANUP_AND_EXIT
;
116 /* Print the result */
123 case 3: matrix_free(&mat3
);
124 case 2: matrix_free(&mat2
);
125 case 1: matrix_free(&mat1
);
126 case 0: ; /* free nothing */
132 mmret_t
matrix_alloc(matrix_t
**mat
, size_t rows
, size_t cols
)
134 size_t i
, j
, mdepth
= 0;
136 *mat
= malloc(sizeof **mat
);
138 goto CLEANUP_AND_RETURN
;
144 (*mat
)->data
= malloc(rows
* sizeof(int *));
145 if ((*mat
)->data
== NULL
)
146 goto CLEANUP_AND_RETURN
;
149 for (i
= 0; i
< rows
; i
++) {
150 (*mat
)->data
[i
] = malloc(cols
* sizeof(int));
151 if ((*mat
)->data
[i
] == NULL
) {
154 goto CLEANUP_AND_RETURN
;
163 case 3: for (j
= 0; j
< i
; j
++) free((*mat
)->data
[j
]);
164 case 2: free((*mat
)->data
);
166 case 0: ; /* free nothing */
172 void matrix_free(matrix_t
**mat
)
176 for (i
= 0; i
< (*mat
)->rows
; i
++)
177 free((*mat
)->data
[i
]);
183 mmret_t
matrix_read(const char *path
, matrix_t
**mat
)
186 size_t i
, j
, rows
, cols
;
189 if ((fp
= fopen(path
, "r")) == NULL
) {
190 fprintf(stderr
, "Error opening file: %s\n", path
);
194 /* Read matrix dimensions */
195 fscanf(fp
, "%u%u", &rows
, &cols
);
197 /* Allocate memory for matrix */
198 if (matrix_alloc(mat
, rows
, cols
) == MM_ENOMEM
) {
203 /* Read matrix elements */
204 for (i
= 0; i
< (*mat
)->rows
; i
++) {
205 for (j
= 0; j
< (*mat
)->cols
; j
++) {
206 fscanf(fp
, "%d", &(*mat
)->data
[i
][j
]);
216 void matrix_print(const matrix_t
*mat
)
220 for (i
= 0; i
< mat
->rows
; i
++) {
221 for (j
= 0; j
< mat
->cols
; j
++) {
222 printf("%d ", mat
->data
[i
][j
]);
229 void *mulvect(void *arg
)
233 row
= *((int *)arg
+ 0);
234 col
= *((int *)arg
+ 1);
236 mat3
->data
[row
][col
] = 0;
237 for (i
= 0; i
< mat1
->cols
; i
++)
238 mat3
->data
[row
][col
] += mat1
->data
[row
][i
] * mat2
->data
[i
][col
];
243 void diep(const char *s
)