pthreads changed
[eleutheria.git] / pthreads / matrixmul / matrixmul.c
blob1fbf5b4885827f1dc7f2fd471c14a583f5e097f4
1 /*
2 * Compile with:
3 * gcc matrixmul.c -o matrixmul -lpthread -Wall -W -Wextra -ansi -pedantic
4 */
6 #include <stdio.h>
7 #include <stdlib.h>
8 #include <pthread.h>
10 typedef struct matrix {
11 size_t rows;
12 size_t cols;
13 int **data;
14 } matrix_t;
16 typedef struct matrix_index {
17 size_t row;
18 size_t col;
19 } matindex_t;
21 typedef enum {
22 MM_OK,
23 MM_ENOMEM,
24 MM_EIO
25 } mmret_t;
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[])
39 pthread_t *tid;
40 matindex_t *v;
41 size_t i, j, k, mdepth, numthreads;
43 /* Check argument count */
44 if (argc != 3) {
45 fprintf(stderr, "Usage: %s matfile1 matfile2\n", argv[0]);
46 exit(EXIT_FAILURE);
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.
56 mdepth = 0;
58 /* Read matrix data from files */
59 if (matrix_read(argv[1], &mat1) != MM_OK)
60 goto CLEANUP_AND_EXIT;
61 mdepth++;
63 if (matrix_read(argv[2], &mat2) != MM_OK)
64 goto CLEANUP_AND_EXIT;
65 mdepth++;
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;
76 mdepth++;
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) {
83 perror("malloc");
84 goto CLEANUP_AND_EXIT;
86 mdepth++;
88 /* Allocate memory for the threads' ids */
89 if ((tid = malloc(numthreads * sizeof *tid)) == NULL) {
90 perror("malloc");
91 goto CLEANUP_AND_EXIT;
93 mdepth++;
95 /* Create the threads */
96 for (i = 0; i < mat1->rows; i++) {
97 for (j = 0; j < mat2->cols; j++) {
98 k = i*mat1->rows + j;
99 v[k].row = i;
100 v[k].col = 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 */
116 matrix_print(mat3);
118 CLEANUP_AND_EXIT:;
119 switch(mdepth) {
120 case 5: free(tid);
121 case 4: free(v);
122 case 3: matrix_free(&mat3);
123 case 2: matrix_free(&mat2);
124 case 1: matrix_free(&mat1);
125 case 0: ; /* free nothing */
128 return EXIT_SUCCESS;
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);
136 if (*mat == NULL)
137 goto CLEANUP_AND_RETURN;
138 mdepth++;
140 (*mat)->rows = rows;
141 (*mat)->cols = cols;
143 (*mat)->data = malloc(rows * sizeof(int *));
144 if ((*mat)->data == NULL)
145 goto CLEANUP_AND_RETURN;
146 mdepth++;
148 for (i = 0; i < rows; i++) {
149 (*mat)->data[i] = malloc(cols * sizeof(int));
150 if ((*mat)->data[i] == NULL) {
151 if (i != 0)
152 mdepth++;
153 goto CLEANUP_AND_RETURN;
157 return MM_OK;
159 CLEANUP_AND_RETURN:;
160 perror("malloc");
161 switch(mdepth) {
162 case 3: for (j = 0; j < i; j++) free((*mat)->data[j]);
163 case 2: free((*mat)->data);
164 case 1: free(*mat);
165 case 0: ; /* free nothing */
168 return MM_ENOMEM;
171 void matrix_free(matrix_t **mat)
173 size_t i;
175 for (i = 0; i < (*mat)->rows; i++)
176 free((*mat)->data[i]);
178 free((*mat)->data);
179 free(*mat);
182 mmret_t matrix_read(const char *path, matrix_t **mat)
184 FILE *fp;
185 size_t i, j, rows, cols;
187 /* Open file */
188 if ((fp = fopen(path, "r")) == NULL) {
189 fprintf(stderr, "Error opening file: %s\n", path);
190 return MM_EIO;
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) {
198 fclose(fp);
199 return 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]);
209 /* Close file */
210 fclose(fp);
212 return MM_OK;
215 void matrix_print(const matrix_t *mat)
217 size_t i, j;
219 for (i = 0; i < mat->rows; i++) {
220 for (j = 0; j < mat->cols; j++) {
221 printf("%d ", mat->data[i][j]);
223 printf("\n");
228 void *mulvect(void *arg)
230 size_t i, row, col;
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];
239 pthread_exit(NULL);
242 void diep(const char *s)
244 perror(s);
245 exit(EXIT_FAILURE);