uni

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

ex1_1.c (3266B)


      1 #include <err.h>
      2 #include <pthread.h>
      3 #include <semaphore.h>
      4 #include <stdio.h>
      5 #include <stdlib.h>
      6 #include <string.h>
      7 #include <unistd.h>
      8 
      9 /*
     10  * Εργαστήριο ΛΣ2 (Δ6) / Εργασία 2: Άσκηση 1.1 / 2020-2021
     11  * Ονοματεπώνυμο: Χρήστος Μαργιώλης
     12  * ΑΜ: 19390133
     13  * Τρόπος μεταγλώττισης: `cc ex1_1.c -lpthread -lrt -o ex1_1`
     14  */
     15 
     16 /* Calculate an array's length. */
     17 #define LEN(x) (sizeof(x) / sizeof(x[0]))
     18 
     19 struct foo {
     20 	char *str;
     21 	int tid;
     22 	sem_t sem;
     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 /* 
     33  * Each thread will print one of these. Everything will adapt in case more
     34  * strings are added to the array. 
     35  */
     36 static const char *nums[] = {
     37 	"<one>",
     38 	"<two>",
     39 	"<three>",
     40 };
     41 
     42 static void *
     43 thread_callback(void *foo)
     44 {
     45 	struct foo *f;
     46 	
     47 	f = (struct foo *)foo;
     48 	/* Lock the semaphore (decrement by one). */
     49 	if (sem_wait(&f->sem) < 0)
     50 		err(1, "sem_wait");
     51 	/* 
     52 	 * Get appropriate string. `f->tid` has the thread's ID -- we'll use
     53 	 * it to give each thread a unique string. Thread 0 will get the first
     54 	 * string, thread 1 the second, and so on.
     55 	 */
     56 	if ((f->str = strdup(nums[f->tid++])) == NULL)
     57 		err(1, "strdup");
     58 	fputs(f->str, stdout);
     59 	free(f->str);
     60 	/* Unlock the semaphore (increment by one). */
     61 	if (sem_post(&f->sem) < 0)
     62 		err(1, "sem_post");
     63 
     64 	return NULL;
     65 }
     66 
     67 static void *
     68 emalloc(size_t nb)
     69 {
     70 	void *p;
     71 
     72 	if ((p = malloc(nb)) == NULL)
     73 		err(1, "malloc");
     74 
     75 	return p;
     76 }
     77 
     78 static void
     79 usage(void)
     80 {
     81 	fprintf(stderr, "usage: %s [-n times]\n", argv0);
     82 	exit(1);
     83 }
     84 
     85 int
     86 main(int argc, char *argv[])
     87 {
     88 	struct foo *f;
     89 	pthread_t *tds;
     90 	int i, len, n = 5;
     91 	char ch;
     92 
     93 	argv0 = *argv;
     94 	while ((ch = getopt(argc, argv, "n:")) != -1) {
     95 		switch (ch) {
     96 		case 'n':
     97 			/* 
     98 			 * Manually choose how many times the string sequence
     99 			 * is going to be printed. Obviously, we cannot allow
    100 			 * an N less than 1. By default `n` is 5 (see 
    101 			 * declaration above).
    102 			 */
    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 	/*
    116 	 * Instead of hardcoding how many threads we want to have, the
    117 	 * number of threads is always equal to how many elements the
    118 	 * `nums` array has. That means in case we want to add/remove
    119 	 * entries from `nums`, everything will adapt automatically.
    120 	 */
    121 	tds = emalloc(len * sizeof(pthread_t));
    122 	f = emalloc(sizeof(struct foo));
    123 
    124 	/* 
    125 	 * sem_init(3)'s second argument defines whether the semaphore
    126 	 * should be shared by multiple processes or not. This is done
    127 	 * by passing a non-zero value, but in this case we want the
    128 	 * semaphore to be shared only by this process.
    129 	 */
    130 	if (sem_init(&f->sem, 0, 1) < 0)
    131 		err(1, "sem_init");
    132 
    133 	while (n--) {
    134 		f->tid = 0;
    135 		for (i = 0; i < len; i++)
    136 			if (pthread_create(&tds[i], NULL,
    137 			    thread_callback, (void *)f) != 0)
    138 				err(1, "pthread_create");
    139 		for (i = 0; i < len; i++)
    140 			if (pthread_join(tds[i], NULL) != 0)
    141 				err(1, "pthread_join");
    142 	}
    143 	printf("\n");
    144 
    145 	(void)sem_destroy(&f->sem);
    146 	pthread_exit(NULL);
    147 	free(tds);
    148 	free(f);
    149 
    150 	return 0;
    151 }