uni

University stuff
git clone git://git.margiolis.net/uni.git
Log | Files | Refs | README | LICENSE

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 }