diff --git a/projet j3/facto.c b/projet j3/facto.c
new file mode 100644
index 0000000000000000000000000000000000000000..6057212b5e825fa1c0c67de0b498e51f56a077e2
--- /dev/null
+++ b/projet j3/facto.c	
@@ -0,0 +1,474 @@
+#include <CUnit/CUnit.h>
+#include <CUnit/Basic.h>
+#include <CUnit/Automated.h>
+#include <stdio.h>
+#include <math.h>
+#include <malloc.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <sys/mman.h>
+#include <string.h>
+#include <stdlib.h>
+#include <semaphore.h>
+#include <pthread.h>
+#include <unistd.h>
+#include <time.h>
+
+
+/**
+* Structure node
+*
+* @next: pointer to the next node in the list, NULL if last node_t
+* @value: value stored in the node
+*/
+typedef struct node {
+    struct node *next;
+    int value;
+} node_t;
+
+
+/**
+* Structure list
+*
+* @first: first node of the list, NULL if list is empty
+* @size: number of nodes in the list
+*/
+typedef struct list {
+    struct node *first;
+    struct node *last;
+    int size;
+} list_t;
+
+
+/**
+ * Structure args_thr
+ * 
+ * Cette structure a été crée afin de pouvoir donner plusieurs arguments aux fonctions exécutées par les threads
+ */
+typedef struct args_thr {
+  int *arg1;
+  list_t *arg2;
+} args_thr_t;
+
+/*
+* Create a new node containing the value @value.
+*
+* @value: value stored in the node
+* @next : pointer to next node, initialised to NULL.
+* @return: returns the pointer to the newly created node, or NULL if an error occured.
+*/
+node_t *init_node(int value) {
+    node_t* new = (node_t*) malloc(sizeof(node_t));
+
+    if(new == NULL){
+        return NULL;
+    }
+
+    new -> value = value;
+    new -> next = NULL;
+
+    return new;
+}
+
+
+//tg fdp
+/*
+* Add a node at the head of the list @list and increment the number of nodes in the list (member `size`)
+*
+* @l: linked list
+* @value: value to add to the list
+*
+* @return: 0 if success, 1 otherwise
+*/
+int add_node(list_t *list, int value) {
+    if(list == NULL){
+        return 1;
+    }
+
+    node_t* new = init_node(value);
+    if(new == NULL){
+        return 1;
+    }
+
+    if(list->size == 0){
+      list->first = new;
+      list->last = new;
+      list->size++;
+    } else{
+      (list->last)->next = new;
+      list->last = new;
+      list->size++;
+    }
+    return 0;
+}
+
+
+
+/*
+* Factorize the number @num into prime numbers and put them into a linked list
+*
+* @num: number to factorize in prime numbers
+*
+* @return: a linked list with all prime nubers wich factorize @num
+*/
+list_t* prime_divs(int num) {
+    list_t* prime_dividers;
+    prime_dividers = (list_t*) malloc(sizeof(list_t));
+    if (prime_dividers == NULL){
+        return NULL;
+    }
+    prime_dividers -> first = NULL;
+    prime_dividers -> last = NULL;
+    prime_dividers -> size = 0;
+
+    int max = 1;
+    int n = num;
+    add_node(prime_dividers,num);
+    while(num % 2 == 0){
+      if (max != 2){
+        max = 2;
+        add_node(prime_dividers, 2);
+      }
+      num = num / 2;
+    }
+
+    int i;
+    for (i = 3; i <= sqrt(num); i = i+2){
+
+        while(num % i == 0){
+          if(i != max){
+            max = i;
+            add_node(prime_dividers,i);
+          }
+          num = num/i;
+        }
+
+    }
+    if((num > 2) && (num != max)){
+      if(num != n){
+        add_node(prime_dividers,num);
+      }
+    }
+    return prime_dividers;
+}
+
+
+
+/*
+* Clear the given linked list @list
+*
+* @list: list to be cleared
+*/
+void clear_ls(list_t *list){
+    if (list -> first == NULL){
+        free(list);
+        return;
+    }
+    if (list -> first != NULL){
+        node_t *head = list->first;
+        while (head->next != NULL){
+            node_t *current = head ->next;
+            free(head);
+            head = current;
+
+        }
+        free(head);
+
+        free(list);
+        return;
+    }
+}
+
+/**
+ * Déclaration des variables utilisées dans les fonctions lecture, calcul et ecriture
+ */
+int i;
+int j;
+int k;
+int l;
+int N;
+FILE* fin;
+FILE* fout;
+sem_t empty;
+sem_t full;
+sem_t empty2;
+sem_t full2;
+pthread_mutex_t mutex;
+pthread_mutex_t mutex2;
+int taille = 0;
+int compteurE = 0;
+int compteurC = 0;
+
+/**
+ * Fonction de type producteur (cfr syllabus : Les sémaphores : Problème des producteurs-consommateurs)
+ * Lis le fichier FILE* fin et place les nombres lus dans un buffer.
+ * Le buffer est parcouru grâce à l'indice i et à la variable N, qui est la taille du buffer.
+ * Le nombre de lignes du fichier est aussi récupéré via la variable taille.
+ * On s'arrête quand tout le fichier a été parcouru
+ * 
+ * @buffer : buffer dans lequelles nombres lus seront placés
+ */
+void lecture(int* buffer) {
+  int item;
+  char *line2 = NULL;
+  size_t len2 = 0;
+  while(getline(&line2, &len2, fin) != -1){ //boucle pour parcourir le fichier, getline renvoie -1 quand on arrive à la fin du fichier, lin et len s'incrémentent tout seuls
+    item = atoi(line2); //on stocke le nombre lu dans la variable item
+    sem_wait(&empty);
+    pthread_mutex_lock(&mutex);
+    buffer[i] = item; //on place item (le nombre lu) dans le buffer (safe car mutex)
+    i = ((i+1)%N); //on incrémente l'index à chaque fois qu'on mets un nombre dans le buffer. Quand i (l'indice) est égal à N (taille du buffer) i retombe à 0 grâce au modulo (safe car mutex)
+    pthread_mutex_unlock(&mutex);
+    sem_post(&full);
+  }
+}
+
+/**
+ * Fonction de type consommateur (vis-à-vis de la fonction lecture) et producteur (vis-à-vis de la fonction écriture) (cfr syllabus : Les sémaphores : Problème des producteurs-consommateurs)
+ * Calcule les diviseurs premiers des nombres contenus dans buffer, puis les place dans buffer2
+ * Les buffers sont parcourus par grâce aux indices j, k et à la variable N, qui correspond à la taille des buffers
+ * On s'arrête lorsque tous les nombres à traiter sont traités, donc lorsque la varianble compteurC est égale à la variable taille
+ * 
+ * @buffer: buffer duquel proviennent les nombres à traiter
+ * @buffer2: buffer dans lequel les nombres traités sont stockés
+ */
+void calcul(args_thr_t *input) {
+  list_t *item;
+  int elem;
+  while(compteurC < taille) { //qd le compteur (! différent de compteurE !) est égal à la taille du fichier (donc quand toutes les lignes on été traitées), on s'arrête
+    //partie consomateur
+    sem_wait(&full);
+    pthread_mutex_lock(&mutex);
+    compteurC +=1; //on incrémente un compteur à chaque fois qu'un nombre est traité (variable globale, safe car mutex)
+    int * temp_buf = input->arg1;
+    elem = temp_buf[j]; //on récupère un nombre à traiter dans le buffer et on le place dans la variable elem (safe car mutex)
+    j = ((j+1)%N); //on incrémente l'index à chaque fois qu'on extrait un nombre du buffer. Qd j (l'index) est égal à la taille du buffer (N), j retombe à 0 grâce au modulo (safe car mutex)
+    pthread_mutex_unlock(&mutex);
+    sem_post(&empty);
+    
+    item = prime_divs(elem); //on calcule les diviseurs premiers de elem, et on place la liste obtenue dans item
+    //partie producteur
+    sem_wait(&empty2);
+    pthread_mutex_lock(&mutex2);
+    input ->arg2[k] = *item; //on place un pointeur vers la liste des diviseurs premier dans le deuxième buffer (safe car mutex)
+    k = ((k+1)%N); //vous avez compris comment on incrémente maintenant
+    pthread_mutex_unlock(&mutex2);
+    sem_post(&full2);
+  }
+}
+
+/**
+ * Fonction de type consommateur (cfr syllabus : Les sémaphores : Problème des producteurs-consommateurs)
+ * Place dans le fichier FILE* fout les nombres (et leurs diviseurs premiers, le tout sous forme de liste) contenus dans buffer2
+ * Le buffer est parcouru grâce à l'indice l et à la variable N, qui correspond à la taille du buffer
+ * On s'arrête lorsque toutes les listes on été traitées, donc lorsque la variable compteurE est égale à la variable taille
+ * 
+ * @buffer2: buffer dans lequel les listes de nombres à écrire dans le fichier sont stockés
+ */
+void ecriture(list_t *buffer2) {
+  list_t *item;
+  
+  while(compteurE < taille) { // qd le compteur (! différent de compteurC !) est égal à la taille du fichier (quand on a réécrit toutes les lignes), on s'arrête
+    sem_wait(&full2);
+    pthread_mutex_lock(&mutex2);
+    compteurE += 1; //on incrémente le compteur à chaque fois qu'on écrit un nombre (variable globale, safe car mutex)
+    item = &buffer2[l]; //on récupère la liste pointée par le pointeur à l'index l (safe car mutex)
+    l = ((l+1)%N); //on incrémente comme d'hab, allez voir dans lecture et calcul si vous avez oublié
+    if(item -> size != 0){ //on écrit dans le fichier fout les diviseurs contenus dans la liste, cette partie de code ne vient pas de moi, mais de fact.c (le programme sans les threads)
+          node_t* toprint = (item->first);
+          while(toprint != NULL){
+              fprintf(fout, "%d ", toprint->value);
+              toprint = toprint->next;
+          }
+    }
+    fprintf(fout, "\n");//on va à la ligne dans le fichier fout
+    pthread_mutex_unlock(&mutex2);
+    sem_post(&empty2);
+  }
+  return;
+}
+
+/*
+Algorithme de type producteurs-consommateurs
+* Read de input file @argv[1] wich contain an integer on every single line and write in the output file @argv[2]
+  the factorization of every integers in the corresponding line
+  Le nombre de threads à utiliser est en option
+  En premier lieu on vérifie si le nombre de threads est spécifié
+  Puis, les variables, indices, sémaphores, buffers, fichiers et threads sont initialisés
+  Ensuite, on lis dans le fichier d'input les nombres à traiter, puis on calcule leurs diviseurs premiers
+   (on passe par une structure pour pouvoir donner plusieurs arguments à la fonction utilisée par les threads)
+   et on écrit le résultat dans le fichier d'ouput
+*
+* @argc: number of arguments
+* @argv[]: array of arguments
+*
+* @return: 0 if no problem occured
+*/
+int main(int argc, char *argv[]){
+  clock_t start;
+  clock_t end;
+  start=clock();
+  //si on ne donne pas le nombre de threads, on prends 3 threads par défaut
+  const char* in = argv[1]; //par défaut, path's vers les fichiers d'entrée et de sortie (si le nombre de threads n'est pas spécifié)
+  const char* out = argv[2];
+  N = 6; //deux fois le nombre de threads, plus facile de mettre qq fois N/2 pour le nombre de threads que de chercher tous les modulos et les tailles de buffer dans le programme pour les multiplier par 2
+  
+  if (getopt(argc,argv, "N:") != -1) { //getopt regarde si l'option N est donnée, si non getopt renvoie -1, si oui elle crée optarg et optind 
+    N = 2*atoi(optarg); //optarg = nombre de threads. La raison pour laquelle on le multiplie par deux est qq lignes au-dessus
+    in = argv[optind];// optind = index du prochain argument non optionel.
+    out = argv[optind + 1];// on stocke les path's des fichiers d'entrée et de sortie dans in et out (leur index n'est pas le même que si le nombre de threads n'est pas spécifié)
+  }
+  //on initialise tout ce dont on a besoin
+  pthread_t *threads = (pthread_t *) malloc(sizeof(pthread_t)*(N/2));
+  if (threads == NULL) {
+    fclose(fin);
+    fclose(fout);
+    return 1;}
+  pthread_t lect;
+  pthread_t ecr;
+  int *buffer = (int*)malloc(N*sizeof(int));
+  if (buffer == NULL) {
+    fclose(fin);
+    fclose(fout);
+    free(threads);
+    return 1;}
+  list_t *buffer2 = (list_t*)malloc(N*sizeof(list_t));
+  if (buffer2 == NULL) {
+    fclose(fin);
+    fclose(fout);
+    free(buffer);
+    free(threads);
+    return 1;}
+  pthread_mutex_init(&mutex,NULL);
+  pthread_mutex_init(&mutex2,NULL);
+  sem_init(&empty,0,N);
+  sem_init(&full,0,0);
+  sem_init(&empty2,0,N);
+  sem_init(&full2,0,0);
+  i=0;j=0;k=0;l=0;
+  int x;
+  int err;
+  fin = fopen(in,"r");
+  fout = fopen(out,"w");
+   //on récupère la taille du fichier avant de commencer à travailler si jamais on demande plus de threads qu'il n'y a de lignes dans le fichier
+  char* line = NULL;
+  size_t len = 0;
+  while (getline(&line,&len,fin) != -1) {taille += 1;}
+  free(line);
+  rewind(fin);
+
+  err = pthread_create(&lect,NULL, (void *) lecture, (void *) buffer);//on lance la lecture du fichier d'entrée
+  if (err != 0) {
+    fclose(fin);
+    fclose(fout);
+    sem_destroy(&empty);
+    sem_destroy(&full);
+    sem_destroy(&empty2);
+    sem_destroy(&full2);
+    pthread_mutex_destroy(&mutex);
+    pthread_mutex_destroy(&mutex2);
+    free(buffer);
+    free(buffer2);
+    free(threads);
+    return 1;}
+
+  args_thr_t* bufs = (args_thr_t *) malloc(sizeof(args_thr_t));//on crée une structure pour stocker les arguments de la fonction calcul, car la fonction pthread_create ne prends qu'un seul pointeur vers les arguments de la fonction utilisée
+  if (bufs == NULL) {
+    fclose(fin);
+    fclose(fout);
+    sem_destroy(&empty);
+    sem_destroy(&full);
+    sem_destroy(&empty2);
+    sem_destroy(&full2);
+    pthread_mutex_destroy(&mutex);
+    pthread_mutex_destroy(&mutex2);
+    free(buffer);
+    free(buffer2);
+    free(threads);
+    return 1;}
+
+  if (bufs == NULL) {
+    fclose(fin);
+    fclose(fout);
+    sem_destroy(&empty);
+    sem_destroy(&full);
+    sem_destroy(&empty2);
+    sem_destroy(&full2);
+    pthread_mutex_destroy(&mutex);
+    pthread_mutex_destroy(&mutex2);
+    free(buffer);
+    free(buffer2);
+    free(threads);
+    return 1;}
+  bufs -> arg1 = buffer;
+  bufs -> arg2 = buffer2;
+
+  for(x=0;x<(N/2) && x < taille ;x++) { //on lance les threads de calcul
+    err = pthread_create(&threads[x],NULL,(void *) calcul,(void *) bufs);
+    if (err != 0) {
+      fclose(fin);
+    fclose(fout);
+    sem_destroy(&empty);
+    sem_destroy(&full);
+    sem_destroy(&empty2);
+    sem_destroy(&full2);
+    pthread_mutex_destroy(&mutex);
+    pthread_mutex_destroy(&mutex2);
+    free(buffer);
+    free(buffer2);
+    free(threads);
+      return 1;}// crash test pour le lancement des threads
+  }
+  
+  err = pthread_create(&ecr,NULL, (void *) ecriture, (void *) buffer2);//on lance l'écriture des diviseurs premiers dans le fichier de sortie
+  if (err != 0) {
+    fclose(fin);
+    fclose(fout);
+    sem_destroy(&empty);
+    sem_destroy(&full);
+    sem_destroy(&empty2);
+    sem_destroy(&full2);
+    pthread_mutex_destroy(&mutex);
+    pthread_mutex_destroy(&mutex2);
+    free(buffer);
+    free(buffer2);
+    free(threads);
+    return 1;}
+    
+  err = pthread_join(ecr,NULL);
+  if (err != 0) {
+    fclose(fin);
+    fclose(fout);
+    sem_destroy(&empty);
+    sem_destroy(&full);
+    sem_destroy(&empty2);
+    sem_destroy(&full2);
+    pthread_mutex_destroy(&mutex);
+    pthread_mutex_destroy(&mutex2);
+    free(buffer);
+    free(buffer2);
+    free(threads);
+    return 1;}
+  //on ferme les fichiers et on libère la mémoire.
+  fclose(fin);
+  fclose(fout);
+  sem_destroy(&empty);
+  sem_destroy(&full);
+  sem_destroy(&empty2);
+  sem_destroy(&full2);
+  pthread_mutex_destroy(&mutex);
+  pthread_mutex_destroy(&mutex2);
+  free(buffer);
+  free(buffer2);
+  free(threads);
+  printf("%s\n","End of process." );
+  
+  end=clock();
+  double procTime=(double)(end-start)/CLOCKS_PER_SEC;
+  printf("Processing time = %f ms\n", procTime*pow(10,3));
+    
+
+  return 0;
+}