ex1_2.c (2823B)
1 #include <err.h> 2 #include <pthread.h> 3 #include <stdio.h> 4 #include <stdlib.h> 5 #include <string.h> 6 #include <unistd.h> 7 8 /* 9 * Εργαστήριο ΛΣ2 (Δ6) / Εργασία 2: Άσκηση 1.2 / 2020-2021 10 * Ονοματεπώνυμο: Χρήστος Μαργιώλης 11 * ΑΜ: 19390133 12 * Τρόπος μεταγλώττισης: `cc ex1_2.c -lpthread -o ex1_2` 13 */ 14 15 #define LEN(x) (sizeof(x) / sizeof(x[0])) 16 17 struct foo { 18 char *str; 19 int done; 20 int tid; 21 pthread_mutex_t mtx; 22 pthread_cond_t cv; 23 }; 24 25 /* Function declarations */ 26 static void *thread_callback(void *); 27 static void *emalloc(size_t); 28 static void usage(void); 29 30 /* Global variables */ 31 static char *argv0; 32 static const char *nums[] = { 33 "<one>", 34 "<two>", 35 "<three>", 36 }; 37 38 static void * 39 thread_callback(void *foo) 40 { 41 struct foo *f; 42 43 f = (struct foo *)foo; 44 if (pthread_mutex_lock(&f->mtx) != 0) 45 err(1, "pthread_mutex_lock"); 46 /* 47 * Set the flag to zero so that the other threads will be blocked 48 * with `pthread_cond_wait`. 49 */ 50 f->done = 0; 51 if ((f->str = strdup(nums[f->tid++])) == NULL) 52 err(1, "strdup"); 53 printf("%s", f->str); 54 free(f->str); 55 f->done = 1; 56 57 /* If a thread is not done executing the statements above, wait. */ 58 if (!f->done) { 59 if (pthread_cond_wait(&f->cv, &f->mtx) != 0) 60 err(1, "pthread_cond_wait"); 61 /* We're done, the next threads can do their job now. */ 62 } else { 63 if (pthread_cond_signal(&f->cv) != 0) 64 err(1, "pthread_cond_signal"); 65 } 66 if (pthread_mutex_unlock(&f->mtx) != 0) 67 err(1, "pthread_mutex_unlock"); 68 69 return NULL; 70 } 71 72 static void * 73 emalloc(size_t nb) 74 { 75 void *p; 76 77 if ((p = malloc(nb)) == NULL) 78 err(1, "malloc"); 79 80 return p; 81 } 82 83 static void 84 usage(void) 85 { 86 fprintf(stderr, "usage: %s [-n times]\n", argv0); 87 exit(1); 88 } 89 90 /* Code shared with `ex1_1` is explained in `ex1_1.c`. */ 91 int 92 main(int argc, char *argv[]) 93 { 94 struct foo *f; 95 pthread_t *tds; 96 int i, len, n = 5; 97 char ch; 98 99 argv0 = *argv; 100 while ((ch = getopt(argc, argv, "n:")) != -1) { 101 switch (ch) { 102 case 'n': 103 if ((n = atoi(optarg)) < 1) 104 errx(1, "value must be greater than 1"); 105 break; 106 case '?': 107 default: 108 usage(); 109 } 110 } 111 argc -= optind; 112 argv += optind; 113 114 len = LEN(nums); 115 tds = emalloc(len * sizeof(pthread_t)); 116 f = emalloc(sizeof(struct foo)); 117 118 if (pthread_mutex_init(&f->mtx, NULL) != 0) 119 err(1, "pthread_mutex_init"); 120 if (pthread_cond_init(&f->cv, NULL) != 0) 121 err(1, "pthread_cond_init"); 122 123 while (n--) { 124 f->done = f->tid = 0; 125 for (i = 0; i < len; i++) 126 if (pthread_create(&tds[i], NULL, 127 thread_callback, (void *)f) != 0) 128 err(1, "pthread_create"); 129 for (i = 0; i < len; i++) 130 if (pthread_join(tds[i], NULL) != 0) 131 err(1, "pthread_join"); 132 } 133 printf("\n"); 134 135 (void)pthread_mutex_destroy(&f->mtx); 136 (void)pthread_cond_destroy(&f->cv); 137 pthread_exit(NULL); 138 free(tds); 139 free(f); 140 141 return 0; 142 }