diff --git a/TD/TD8/exercise1a.c b/TD/TD8/exercise1a.c new file mode 100644 index 0000000..b429449 --- /dev/null +++ b/TD/TD8/exercise1a.c @@ -0,0 +1,84 @@ +#include +#include +#include +#include + +#define N 20 +#define PROD 5 +#define CONS 5 +#define PROD_MAX 500 + +int shared_buffer[N]; + +void* producteur(void* args) { + int j, product = 0; + int count = 0; + while (1) { + int i = -1; + while (++i < N) { + if (shared_buffer[i] == -1) { + break; + } + } + if (i >= N) { + sleep(0.05); + continue; + } + product = (rand()%500+product)%20000; + j = (i+j)%20000; + shared_buffer[i] = product; + count++; + if (!(count % 5000)) + printf("produit: %d %d\n", j, product); + sleep(0.05); + } + return NULL; +} + +void* consommateur(void* args) { + int j, product = 0; + int count = 0; + while (1) { + int i = -1; + while (++i < N) { + if (shared_buffer[i] != -1) { + break; + } + } + if (i >= N) { + sleep(0.05); + continue; + } + product = (shared_buffer[i]+product)%20000; + j = (i+j)%20000; + shared_buffer[i] = -1; + count++; + if (!(count %5000)) + printf("résultat: %d %d %d\n", j, product); + sleep(0.05); + } + return NULL; +} + + + +int main() { + for (int i=0; i < N; i++) { + shared_buffer[i] = -1; + } + + pthread_t tid[PROD+CONS]; + for (int i=0; i < PROD; i++) { + pthread_create(&(tid[i]), NULL, &producteur, NULL); + } + + for (int i=0; i < CONS; i++) { + pthread_create(&(tid[i+PROD]), NULL, &consommateur, NULL); + } + + for (int i=0; i < PROD+CONS; i++) { + pthread_join(tid[i], NULL); + } + + return 0; +} diff --git a/TD/TD8/exercise1b.c b/TD/TD8/exercise1b.c new file mode 100644 index 0000000..9641aeb --- /dev/null +++ b/TD/TD8/exercise1b.c @@ -0,0 +1,120 @@ +#include +#include +#include +#include +#include + +#define N 10 +#define PROD 5 +#define CONS 3 +#define PROD_MAX 500 +#define DELAY 1 + +#define RED "\033[31m" +#define RESET "\033[0m" + + +sem_t sem_prod; +sem_t sem_cons; +sem_t sem_renderer; + +int shared_buffer[N]; +pthread_mutex_t lock; + +void* producteur(void* args) { + while (1) { + sem_wait(&sem_prod); + pthread_mutex_lock(&lock); + int i = -1; + while (++i < N) { + if (shared_buffer[i] == -1) { + shared_buffer[i] = rand()%PROD_MAX; + sem_post(&sem_cons); + sem_post(&sem_renderer); + //printf("placed@%d !\n", i); + break; + } + } + if (i >= N) { + fprintf(stderr, "Can't place my product !\n"); + exit(1); + } + pthread_mutex_unlock(&lock); + sleep(DELAY); + } + return NULL; +} + +void* consommateur(void* args) { + while (1) { + sem_wait(&sem_cons); + pthread_mutex_lock(&lock); + int i = -1; + while (++i < N) { + if (shared_buffer[i] != -1) { + shared_buffer[i] = -1; + //printf("got@%d !\n", i); + sem_post(&sem_prod); + sem_post(&sem_renderer); + break; + } + } + if (i >= N) { + fprintf(stderr, "Can't get a product !\n"); + exit(1); + } + pthread_mutex_unlock(&lock); + sleep(DELAY); + } + return NULL; +} + +void* renderer(void* args) { + while (1) { + sem_wait(&sem_renderer); + pthread_mutex_lock(&lock); + printf("\r"); + for (int i=0; i < N; i++) { + if (shared_buffer[i] == -1) { + printf(RED "%3d " RESET, shared_buffer[i]); + } else { + printf("%3d ", shared_buffer[i]); + } + } + pthread_mutex_unlock(&lock); + } +} + + + +int main() { + for (int i=0; i < N; i++) { + shared_buffer[i] = -1; + } + + pthread_mutex_init(&lock, NULL); + + pthread_t tid[PROD+CONS+1]; + sem_init(&sem_prod, 0, N); + sem_init(&sem_cons, 0, 0); + sem_init(&sem_renderer, 0, 1); + for (int i=0; i < PROD; i++) { + pthread_create(&(tid[i]), NULL, &producteur, NULL); + } + + for (int i=0; i < CONS; i++) { + pthread_create(&(tid[i+PROD]), NULL, &consommateur, NULL); + } + + // Additional renderer thread to display the state of the market + pthread_create(&(tid[CONS+PROD]), NULL, &renderer, NULL); + + + for (int i=0; i < PROD+CONS+1; i++) { + pthread_join(tid[i], NULL); + } + sem_destroy(&sem_cons); + sem_destroy(&sem_prod); + + return 0; +} diff --git a/TD/TD8/exercise2.c b/TD/TD8/exercise2.c new file mode 100644 index 0000000..e5c0198 --- /dev/null +++ b/TD/TD8/exercise2.c @@ -0,0 +1,146 @@ +#include +#include +#include +#include + +/* +Ordre des pipes: +AB 0 +AC 1 +AD 2 +BI 3 +CE 4 +CF 5 +DH 6 +EG 7 +FG 8 +GI 9 +HI 10 +IA 11 +*/ + +int main() { + int* fds[12]; + + for (int i=0; i < 12; i++) { + fds[i] = malloc(sizeof(int)*2); + pipe(fds[i]); + } + + int i=0; + for (; i < 9; i++) { + if (fork()) { break; } // Generate 9 processes + if (i == 8) { return 0; } + } + + int input[3] = {-1, -1, -1}; + int output[3] = {-1, -1, -1}; + + char id = 'A'+i; + switch (id) { + case 'A': {// A + input[0] = 11; + output[0] = 0; + output[1] = 1; + output[2] = 2; + } break; + case 'B': {// B + input[0] = 0; + output[0] = 3; + } break; + case 'C': {// C + input[0] = 1; + output[0] = 4; + output[1] = 5; + } break; + case 'D': {// D + input[0] = 2; + output[0] = 6; + } break; + case 'E': {// E + input[0] = 4; + output[0] = 7; + } break; + case 'F': {// F + input[0] = 5; + output[0] = 8; + } break; + case 'G': {// G + input[0] = 7; + input[1] = 8; + output[0] = 9; + } break; + case 'H': {// H + input[0] = 6; + output[0] = 10; + } break; + case 'I': {// I + input[0] = 3; + input[1] = 9; + input[2] = 10; + output[0] = 11; + } break; + default: + return -1; + } + + FILE* in_stream[3]; + FILE* out_stream[3]; + + for (int j=0; j < 3; j++) { + if (input[j] != -1) { + in_stream[j] = fdopen(fds[input[j]][0], "r"); + } + if (output[j] != -1) { + out_stream[j] = fdopen(fds[output[j]][1], "w"); + } + } + + + printf("%c: got %d %d %d > %d %d %d\n", id, input[0], input[1], input[2], output[0], output[1], output[2]); + sleep(1); + + if (id == 'I') { + int c; + while (1) { // Get things from stdin + c = getchar(); + for (int j=0; j < 3; j++) { + if (output[j] != -1) { + fputc(c, out_stream[j]); + } + } + } + return 0; + } + while (1) { + printf("%c listening...\n", id); + + int c, d; + d = -1; + for (int j=0; j < 3; j++) { + if (input[j] != -1) { + c = fgetc(in_stream[j]); + if (d != -1 && c != d) { + fprintf(stderr, "%c got two different chars: %c vs %c\n", id, c, d); + } + d = c; + } + } + printf("%c received %c\n", id, c); + for (int j=0; j < 3; j++) { + if (output[j] != -1) { + printf("%c transmits %c to %d\n", id, c, output[j]); + fputc(c, out_stream[j]); + } + } + } + + for (int j=0; j < 3; j++) { + if (input[j] != -1) { + fclose(in_stream[j]); + } + if (output[j] != -1) { + fclose(out_stream[j]); + } + } +} \ No newline at end of file diff --git a/TD/TD8/index.md b/TD/TD8/index.md new file mode 100644 index 0000000..b90c465 --- /dev/null +++ b/TD/TD8/index.md @@ -0,0 +1,12 @@ +# TD 8: Threads and synchronisation + +## Reasoning operating systems: questions + +1. Différent mécanismes pour différentes utilisations: + - mutex locks pour gérer l'accès à une ressource + - sémaphores pour gérer l'accès à une quantité de variables + - variables de condition + - spin lock: comme sémaphore mais avec du temps processus +2. Cela indique quelles fourchettes sont utilisées, + chaque philosophe n'utilisant que 2 fourchettes ou aucune à la fois +3. Deadlock possible diff --git a/TD/TD9/exercice1.c b/TD/TD9/exercice1.c new file mode 100644 index 0000000..57a64ad --- /dev/null +++ b/TD/TD9/exercice1.c @@ -0,0 +1,69 @@ +#include +#include +#include +#include +#include +#include + +#define N 50 +//#define SHOW_DETAILS + +pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER; + +void* access_res(void* args) { + int id = *(int*)args; + *(int*)args = 0; + + for (int i=0; i < INT_MAX; i++) { + pthread_mutex_lock(&lock); + *(int*)args += 1; + pthread_mutex_unlock(&lock); + } + *(int*)args = -1; + + return NULL; +} + +int main() { + pthread_t tid[N]; + int args[N]; // Reuse it for the number of accesses + + for (int i=0; i < N; i++) { + args[i] = i; + pthread_create(&(tid[i]), NULL, &access_res, (void*)&(args[i])); + } + + bool is_end = false; + while (!is_end) { + #ifdef SHOW_DETAILS + printf("Accesses:\n"); + #endif + int max, min, avg; + max = avg = 0; + min = INT_MAX; + for (int i=0; i < N; i++) { + #ifdef SHOW_DETAILS + printf("%d ", args[i]); + #endif + if (args[i] == -1) + is_end = true; + + if (args[i] > max) + max = args[i]; + + if (args[i] < min) + min = args[i]; + + avg += args[i]/N; + } + #ifdef SHOW_DETAILS + printf("\n"); + #endif + printf("min max avg : %d %d %d\n", min, max, avg); + sleep(1); + } + + for (int i=0; i < N; i++) { + pthread_join(tid[i], NULL); + } +} diff --git a/TD/TD9/exercice2.c b/TD/TD9/exercice2.c new file mode 100644 index 0000000..416bd93 --- /dev/null +++ b/TD/TD9/exercice2.c @@ -0,0 +1,63 @@ +#include +#include +#include +#include +#include + +pthread_mutex_t mutex1 = PTHREAD_MUTEX_INITIALIZER; +pthread_mutex_t mutex2 = PTHREAD_MUTEX_INITIALIZER; +pthread_mutex_t mutex3 = PTHREAD_MUTEX_INITIALIZER; + + +void* process_fun(void* arg) { + int id = *(int*)arg; + bool success = false; + pthread_mutex_t* mutexs[3]; + if (id == 0) { // Gives deadlock sometimes + mutexs[0] = &mutex1; + mutexs[1] = &mutex2; + mutexs[2] = &mutex3; + } else if (id == 1) { + mutexs[0] = &mutex2; + mutexs[1] = &mutex1; + mutexs[2] = &mutex3; + } else if (id == 2) { + mutexs[0] = &mutex1; + mutexs[1] = &mutex2; + mutexs[2] = &mutex3; + } + + while (!success) { + bool csucc = true; + for (int i=0; i < 3; i++) { + if (pthread_mutex_trylock(mutexs[i]) != 0) { + for (int j=0; j < i; j++) { + pthread_mutex_unlock(mutexs[i]); + } + csucc = false; + break; + } + } + success = csucc; + } + printf("I have access\n"); + pthread_mutex_unlock(mutexs[0]); + pthread_mutex_unlock(mutexs[1]); + pthread_mutex_unlock(mutexs[2]); + + return NULL; +} + +int main() { + pthread_t tid[3]; + int args[3]; + + for (int i=0; i < 3; i++) { + args[i] = i; + pthread_create(&(tid[i]), NULL, &process_fun, &(args[i])); + } + + for (int i=0; i < 3; i++) { + pthread_join(tid[i], NULL); + } +} diff --git a/TD/TD9/index.md b/TD/TD9/index.md new file mode 100644 index 0000000..716477d --- /dev/null +++ b/TD/TD9/index.md @@ -0,0 +1,8 @@ +# Deadlocks + +## Reasoning operating systems + +1. Les processus 1 et 4 sont en deadlock. +2. On n'a pas le graphe des tâches qui vont arriver en avance. Donc c'est plus compliqué dans un monde réel +3. 1/6 : same order is deadlock free +