diff --git a/rapport.c b/rapport.c
new file mode 100644
index 0000000000000000000000000000000000000000..64172aaf05f621c6f9f366e5bc9433a866eb1b42
--- /dev/null
+++ b/rapport.c
@@ -0,0 +1,401 @@
+//
+// Created by Giovi on 02/04/2020.
+// Note:
+// PRODUCER-CONSUMER VERSION WITH THREADS, SEMAPHORES AMD MUTEXES
+//
+#include <errno.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <math.h>
+#include <stdbool.h>
+#include <time.h>
+#include <pthread.h>
+#include <semaphore.h>
+
+/* STRUCTURES AND VARIABLES */
+#define NT_READ 1  // Number of threads reading numbers: PRODUCER
+#define NT_WRITE 1  // Number of threads writing number dividers: CONSUMER
+
+/* BUFFER containing numbers used
+ * in read and write operations
+ * Allow the implementation of
+ * Producer-Consumer algorithm
+ */
+#define BUFSIZE 5 /* Max number of elements in the number buffer    */
+#define N 5       /* Max number of elements in the semaphore buffer */
+
+unsigned long buffer[BUFSIZE] = {0};
+int in = 0;
+int out = 0;
+
+/* "struct factorization"
+ * "prime_dividers" is an array containing max N dividers
+ * "cnt" is the number of calculated dividers
+ * "number" is number to calculate the prime dividers
+ */
+typedef struct factorization {
+    unsigned long prime_dividers[N];
+    unsigned int cnt;
+    unsigned long number;
+} factor;
+
+/* struct file_descriptors
+ * "in" is the inputfile file descriptor
+ * "out" is the outputfile file descriptor
+ * "options" "v" (verbose) with debugging information, "q" without debugging information
+ */
+typedef struct file_descriptors {
+    FILE *in;
+    FILE *out;
+    char options;
+} fd;
+
+/* Additional buffer used to put in memory
+ * all the numbers stored in the input file.
+ * "#define MAXELEM 120" can be tuned according
+ * how many numbers (lines) are in the input file.
+ * The following bash command can be used:
+ * wc -l file.txt
+ */
+#define MAXELEM 120 //
+unsigned long Array_Numbers[MAXELEM];
+unsigned int n_arry = 0;
+
+/* MUTEX  */
+pthread_mutex_t mutex_readwrite;
+/* This additional Mutex has been eliminated in the PRODUCER-CONSUMER VERSION */
+// pthread_mutex_t mutex_dividers;
+/* SEMAPHORE for critical section */
+sem_t empty;
+sem_t full;
+
+/*
+* FUNCTIONS used in the programme:
+* bool is_div(unsigned long, unsigned long);
+* bool is_prime(unsigned long);
+* factor *prime_divs(unsigned long);
+* void *read_numbers(FILE *fd) - PRODUCER
+* void *write_dividers(FILE *fd) - CONSUMER
+*/
+bool is_div(unsigned long numbr, unsigned long i){
+    if((numbr % i) == 0) {  // verify if i is the divider of numbr
+        return(true); // i is a divider of numbr
+    } else {
+        return(false); // i is not a divider of numbr
+    }
+}
+
+bool is_prime(unsigned long nbr) {
+ /*
+  * Optimised solution with less loop, see: https://fr.wikipedia.org/wiki/Nombre_premier
+  * "Crible d'Ératosthène:
+  * Les premiers algorithmes pour décider si un nombre est premier
+  * (appelés tests de primalité) consistent à essayer de le diviser par tous les nombres
+  *  qui n'excèdent pas sa racine carrée"
+  */
+// for(unsigned long j = 2; j <= nbr; j++) { // OLD SOLUTION LESS EFFICIENT
+    for (unsigned long j = 2; j <= sqrt(nbr); j++) {
+        if ((nbr % j) == 0) {  // verify if i is the divider of nbr
+            return (false); // i is a divider of nbr but not prime
+        }
+    }
+    return (true); // "yes": i is a prime number
+}
+
+factor* prime_divs (unsigned long numbr) {
+/* Allocation of memory for "struct factor"
+ * Initialize the structure "dividers"  to zero
+ */
+    factor *dividers;
+    // Intialize dividers struct ("struct factor")
+    dividers = (factor *) calloc(1, sizeof(factor));
+
+    unsigned int n = 0;
+    dividers->number = numbr;
+    unsigned long tmp_number = dividers->number;
+    // Old Python code line translated in C
+    // "for(unsigned long i = 2; i < number; i++) {"
+    for(unsigned long i = 2; i <= tmp_number ; i++) { /* OPTIMIZED VERSION */
+        if(is_div(dividers->number,i) == true){
+            if(is_prime(i) == true){
+                dividers->prime_dividers[n] = i;
+                /* The max numbers of loops is reduced
+                 * from "number" to "tmp_number/i"
+                 */
+                tmp_number = tmp_number/i;
+                if(i != dividers->number) {
+                    n++;
+                }
+            }
+        }
+    }
+    dividers->cnt = n;
+    return (dividers);
+}
+
+/*  PRODUCER  */
+void* producer(fd *f) {
+    unsigned long nummer;
+    /* OPTIONS
+     * for( ; (fscanf(f->in, "%lu", &nummer) && (!feof(f->in))) ; ) {
+     * while (!feof(f->in)) {
+     */
+    for(int j = 0; j < n_arry; j++) {
+        nummer = Array_Numbers[j];
+        if (f->options == 'v') {
+            printf("Producer - read number: %lu\n", nummer);
+        }
+        /* Critical section */
+        sem_wait(&empty);
+        pthread_mutex_lock(&mutex_readwrite);
+
+        buffer[in] = nummer;
+        if (f->options == 'v') {
+            printf("Producer, Number in the buffer: %lu [%d]\n", buffer[in], in);
+        }
+        in = (in + 1) % BUFSIZE;
+
+        if (f->options == 'v') {
+            printf("Producer, New buffer index: [%d]\n", in);
+        }
+
+        // End critical section
+        pthread_mutex_unlock(&mutex_readwrite);
+        sem_post(&full);               // End critical section
+    }
+    if (f->options == 'v') {
+        printf("Producer: EOF\n");
+    }
+    pthread_exit((void*)0); // thread exit: normal termination => 0
+}
+
+/*  CONSUMER  */
+void *consumer(fd *f) {
+    factor *dividers; // Structure storing dividers and their number
+    unsigned long number = 0;
+    unsigned int elements = 0;
+
+    while(elements < n_arry) {
+        // read the number from the buffer
+        sem_wait(&full);              // Critical section //////ERROR
+        pthread_mutex_lock(&mutex_readwrite);
+        number = buffer[out];
+        if (f->options == 'v') {
+            printf("Consumer - number in the buffer %lu\n", buffer[out]);
+            printf("Consumer - index of the buffer [%d]\n", out);
+        }
+        out = (out + 1) % BUFSIZE;
+        pthread_mutex_unlock(&mutex_readwrite);
+        sem_post(&empty);              // End critical section
+///
+        if(f->options == 'v') {
+            printf("Consumer - new index of the buffer %d\n", out);
+        }
+        /* Verify if the number is prime or not, in this case the dividers are calculated */
+        dividers = prime_divs(number); // Core function of the app //
+///
+        if(f->options == 'v') {
+            printf("\nConsumer - Write number: %lu ", dividers->number);
+        }
+        /* This additional Mutex has been eliminated in the PRODUCER-CONSUMER VERSION */
+        // MUTEX LOCK
+        /*
+        if (pthread_mutex_lock(&mutex_dividers) != 0){
+            printf("\nConsumer - lock mutex_dividers ERROR %s\n", strerror(errno));
+            exit(EXIT_FAILURE);
+        }
+         */
+        fprintf(f->out, "Number: %lu ", dividers->number);
+        if(dividers->cnt != 0) {
+            for(int i = 0; i < dividers->cnt; i++) {
+                if(f->options == 'v') {
+                    printf("%lu ", dividers->prime_dividers[i]);
+                }
+                fprintf(f->out, " %lu", dividers->prime_dividers[i]);
+            }
+        } else {
+            fprintf(f->out, "This is a prime number");
+            if(f->options == 'v') {
+                printf("This is a prime number");
+            }
+        }
+        /* This additional Mutex has been eliminated in the PRODUCER-CONSUMER VERSION */
+        // MUTEX UNLOCK
+        /*
+        if (pthread_mutex_unlock(&mutex_dividers) != 0){
+            printf("\nConsumer - unlock mutex_readwrite ERROR %s\n", strerror(errno));
+            exit(EXIT_FAILURE);
+        }
+         */
+        fprintf(f->out, "\n");
+        free(dividers);
+        elements++;  // New loop
+    }
+    pthread_exit((void*)0); // thread exit: normal termination => 0;;
+}
+
+/******************
+ * MAIN PROGRAMME *
+ *****************/
+int main (int argc, char *argv[]) {
+// Declare f (type fd). Structure containing the file descriptors
+    fd *f;
+    // Allocation of memory for "struct file_descriptors"
+    f = (fd *) calloc(1, sizeof(fd));
+    // Inputfile and outputfile arguments
+    char *inputfile;  // Input filemane (string)
+    char *outputfile; // Output filemane (string)
+
+    pthread_t p_thread[NT_READ]; // thread IDs     // PRODUCER THREADS
+    pthread_t c_thread[NT_WRITE]; // thread IDs    // CONSUMER THREADS
+/*
+ * START CLOCK to measure CPU time
+ * calculate programme performance
+ */
+    clock_t start, end;
+    double cpu_time_used;
+    start = clock();
+
+    /*  Check if the number of arguments is correct  */
+    if (argc == 4) {
+        inputfile = argv[1];
+        outputfile = argv[2];
+        char *opt = argv[3]; // v or q
+        f->options = *opt;
+    } else {
+        printf("%s\n", "Many or few arguments");
+        exit(EXIT_FAILURE);
+    }
+    if (f->options == 'v') {
+        system("pwd"); // Current directory
+        printf("\n -- Programme start --\n");
+        printf(" nr arguments: %d\n", argc);
+        printf(" input file: %s\n", inputfile);
+        printf(" output file: %s\n", outputfile);
+        printf(" option: %c\n\n", f->options);
+    }
+
+// Initialize the buffer containig the numbers
+    memset(&buffer, 0, BUFSIZE *  sizeof(unsigned long));
+
+    if(f->options == 'v') {
+        printf("Initialize semaphore\n");
+    }
+    // Initialize semaphores
+    sem_init(&empty, 0 , N);        // buffer vide
+    sem_init(&full, 0 , 0);  // buffer vide
+
+    if(f->options == 'v') {
+        printf("Initialize mutex\n");
+    }
+    // INITIALIZE MUTEX "mutex_readwrite"
+    if (pthread_mutex_init(&mutex_readwrite , NULL) != 0){
+        printf("\n mutex init failed-mutex_readwrite\n");
+        exit(EXIT_FAILURE);
+    }
+    /* This additional Mutex has been eliminated in the PRODUCER-CONSUMER VERSION */
+    /*
+    if (pthread_mutex_init(&mutex_dividers , NULL) != 0){
+        printf("\n mutex init failed-mutex_readwrite\n");
+        exit(EXIT_FAILURE);
+    }
+    */
+    // Open input and output files
+    if(f->options == 'v') {
+        printf("Create input & output file descriptors\n");
+    }
+    f->in = fopen(inputfile, "r");
+    f->out = fopen(outputfile, "a+");
+    if ((f->in == NULL) || (f->out == NULL)) {
+        exit(EXIT_FAILURE);
+    }
+    /* Read all numbers from the input file and put them in an array
+     * to speed up the divisors calculation
+     */
+    unsigned long numero;
+    while(!feof(f->in)) {
+        fscanf(f->in, "%lu\n", &numero);
+        if(f->options == 'v') {
+            printf("%d. Number %lu\n",n_arry, numero);
+        }
+        Array_Numbers[n_arry] = numero;
+        n_arry++;
+        // Check and message to inform about the maximum number array elements
+        // tha are allowed. The max can be tuned
+        if(n_arry > MAXELEM) {
+            printf("Please increase the maximum number of array elements (size),\n");
+            printf("you must increase the MAXELEM constant in the c programme\n");
+            printf("In particular increase \"120\" in the following code line => #define MAXELEM 120\n");
+            printf("Thanks :)\n");
+            exit(EXIT_FAILURE);
+        }
+    }
+// ACTIVATE THREADS - CONSUMER-PRODUCER
+    if(f->options == 'v') {
+        printf("Create Threads\n");
+    }
+    for (int i = 0; i < NT_READ; i++) {
+        pthread_create(&p_thread[i], NULL, (void*)producer, f);
+        if (f->options == 'v') {
+            printf("\nMain: create thread n.%d Producer\n", i+1);
+        }
+    }
+    for (int i = 0; i < NT_WRITE; i++) {
+        pthread_create(&c_thread[i], NULL, (void*)consumer, f);
+        if (f->options == 'v') {
+            printf("\nMain: create  thread n.%d Consumer\n", i+1);
+        }
+    }
+    /*  JOIN THREADS  */
+    for (int i = 0; i < NT_READ; i++) {
+        pthread_join(p_thread[i], NULL);
+        if (f->options == 'v') {
+            printf("\nMain: join thread n.%d Producer\n", i+1);
+        }
+    }
+    for (int i = 0; i < NT_WRITE; i++) {
+        pthread_join(c_thread[i], NULL);
+        if (f->options == 'v') {
+            printf("\nMain: join thread n.%d Consumer\n", i+1);
+        }
+    }
+    /* END CLOCK to measure CPU time */
+    end = clock();
+    cpu_time_used = ((double) (end - start)) / CLOCKS_PER_SEC;
+    fprintf(f->out, "\nThe programme execution needed %.3f seconds\n\n", cpu_time_used);
+    // Print on the "stdout"
+    printf("\nThe programme execution needed %.3f seconds\n\n", cpu_time_used);
+
+    // Eliminate semaphores
+    if (sem_destroy(&empty) != 0){
+        printf("\nSem destroy Empty %s\n", strerror(errno));
+        exit(EXIT_FAILURE);
+    }
+    if (sem_destroy(&full) != 0){
+        printf("\nSem destroy Full %s\n", strerror(errno));
+        exit(EXIT_FAILURE);
+    }
+    // Eliminate mutex "mutex_readwrite"
+    if (pthread_mutex_destroy(&mutex_readwrite) != 0){
+        printf("\nmutex_destroy-mutex_readwrite %s\n", strerror(errno));
+        fclose(f->in);
+        fclose(f->out);
+        exit(EXIT_FAILURE);
+    }
+    /* This additional Mutex has been eliminated in the PRODUCER-CONSUMER VERSION */
+    /*
+    if (pthread_mutex_destroy(&mutex_dividers) != 0){
+        printf("\nmutex_destroy-mutex_dividers %s\n", strerror(errno));
+    }
+    */
+    fclose(f->in);
+    fclose(f->out);
+    free(f);  // Free the memory allocated with malloc
+
+    return (EXIT_SUCCESS);
+}
\ No newline at end of file