Constify some variables
[eleutheria.git] / pthreads / matrixmul.c
blobdc60e80f6920cb010b1273098252aefb23d0c2e9
1 /* compile with:
2 gcc matrixmul.c -o matrixmul -lpthread -Wall -W -Wextra -ansi -pedantic */
4 #include <stdio.h>
5 #include <stdlib.h>
6 #include <pthread.h>
8 struct matrix {
9 unsigned int rows;
10 unsigned int cols;
11 int **data;
14 struct matrix_index {
15 unsigned int row;
16 unsigned int col;
19 typedef enum {
20 mm_error_none,
21 mm_error_no_memory,
22 mm_error_io
23 } mm_error;
25 /* function prototypes */
26 mm_error matrix_alloc(struct matrix **mat, unsigned int rows, unsigned int cols);
27 void matrix_free(struct matrix **mat);
28 mm_error matrix_read(const char *path, struct matrix **mat);
29 void matrix_print(const struct matrix *mat);
30 void *mulvect(void *arg);
31 void diep(const char *s);
33 int main(int argc, char *argv[])
35 pthread_t *tid;
36 struct matrix_index *v;
37 unsigned int i, j, k, mdepth = 0, numthreads;
39 /* check argument count */
40 if (argc != 3) {
41 fprintf(stderr, "Usage: %s matfile1 matfile2\n", argv[0]);
42 exit(EXIT_FAILURE);
45 /* read matrix data from files */
46 if (matrix_read(argv[1], &mat1) != mm_error_none)
47 goto CLEANUP_AND_EXIT;
48 mdepth++;
50 if (matrix_read(argv[2], &mat2) != mm_error_none)
51 goto CLEANUP_AND_EXIT;
52 mdepth++;
54 /* is the multiplication feasible by definition? */
55 if (mat1->cols != mat2->rows) {
56 fprintf(stderr, "Matrices' dimensions size must satisfy (NxM)(MxK)=(NxK)\n");
57 goto CLEANUP_AND_EXIT;
60 /* allocate memory for the result */
61 if (matrix_alloc(&mat3, mat1->rows, mat2->cols) != mm_error_none)
62 goto CLEANUP_AND_EXIT;
63 mdepth++;
65 /* how many threads do we need ? */
66 numthreads = mat1->rows * mat2->cols;
68 /* v[k] holds the (i, j) pair in the k-th computation */
69 if ((v = malloc(numthreads * sizeof *v)) == NULL) {
70 perror("malloc");
71 goto CLEANUP_AND_EXIT;
73 mdepth++;
75 /* allocate memory for the threads' ids */
76 if ((tid = malloc(numthreads * sizeof *tid)) == NULL) {
77 perror("malloc");
78 goto CLEANUP_AND_EXIT;
80 mdepth++;
82 /* create the threads */
83 for (i = 0; i < mat1->rows; i++) {
84 for (j = 0; j < mat2->cols; j++) {
85 k = i*mat1->rows + j;
86 v[k].row = i;
87 v[k].col = j;
88 if (pthread_create(&tid[k], NULL, mulvect, (void *)&v[k])) {
89 perror("pthread_create");
90 goto CLEANUP_AND_EXIT;
95 /* make sure all threads are done */
96 for (i = 0; i < numthreads; i++)
97 if (pthread_join(tid[i], NULL)) {
98 perror("pthread_join");
99 goto CLEANUP_AND_EXIT;
102 /* print the result */
103 matrix_print(mat3);
105 CLEANUP_AND_EXIT:;
106 switch(mdepth) {
107 case 5:
108 free(tid);
109 case 4:
110 free(v);
111 case 3:
112 matrix_free(&mat3);
113 case 2:
114 matrix_free(&mat2);
115 case 1:
116 matrix_free(&mat1);
117 case 0:
118 ; /* free nothing */
121 return EXIT_SUCCESS;
124 mm_error matrix_alloc(struct matrix **mat, unsigned int rows, unsigned int cols)
126 unsigned int i, j, mdepth = 0;
128 *mat = malloc(sizeof **mat);
129 if (*mat == NULL)
130 goto CLEANUP_AND_RETURN;
131 mdepth++;
133 (*mat)->rows = rows;
134 (*mat)->cols = cols;
136 (*mat)->data = malloc(rows * sizeof(int *));
137 if ((*mat)->data == NULL)
138 goto CLEANUP_AND_RETURN;
139 mdepth++;
141 for (i = 0; i < rows; i++) {
142 (*mat)->data[i] = malloc(cols * sizeof(int));
143 if ((*mat)->data[i] == NULL) {
144 if (i != 0)
145 mdepth++;
146 goto CLEANUP_AND_RETURN;
149 return mm_error_none;
151 CLEANUP_AND_RETURN:;
152 perror("malloc");
153 switch(mdepth) {
154 case 3:
155 for (j = 0; j < i; j++)
156 free((*mat)->data[j]);
157 case 2:
158 free((*mat)->data);
159 case 1:
160 free(*mat);
161 case 0:
162 ; /* free nothing */
165 return mm_error_no_memory;
168 void matrix_free(struct matrix **mat)
170 unsigned int i;
172 for (i = 0; i < (*mat)->rows; i++)
173 free((*mat)->data[i]);
175 free(*mat);
178 mm_error matrix_read(const char *path, struct matrix **mat)
180 FILE *fp;
181 unsigned int i, j, rows, cols;
183 /* open file */
184 if ((fp = fopen(path, "r")) == NULL) {
185 fprintf(stderr, "Error opening file: %s\n", path);
186 return mm_error_io;
189 /* read matrix dimensions */
190 fscanf(fp, "%u%u", &rows, &cols);
192 /* allocate memory for matrix */
193 if (matrix_alloc(mat, rows, cols) == mm_error_no_memory) {
194 fclose(fp);
195 return mm_error_no_memory;
198 /* read matrix elements */
199 for (i = 0; i < (*mat)->rows; i++) {
200 for (j = 0; j < (*mat)->cols; j++) {
201 fscanf(fp, "%d", &(*mat)->data[i][j]);
205 /* close file */
206 fclose(fp);
208 return mm_error_none;
211 void matrix_print(const struct matrix *mat)
213 unsigned int i, j;
215 for (i = 0; i < mat->rows; i++) {
216 for (j = 0; j < mat->cols; j++) {
217 printf("%d ", mat->data[i][j]);
219 printf("\n");
224 void *mulvect(void *arg)
226 unsigned int i, row, col;
228 row = *((int *)arg + 0);
229 col = *((int *)arg + 1);
231 mat3->data[row][col] = 0;
232 for (i = 0; i < mat1->cols; i++)
233 mat3->data[row][col] += mat1->data[row][i] * mat2->data[i][col];
235 pthread_exit(NULL);
238 void diep(const char *s)
240 perror(s);
241 exit(EXIT_FAILURE);