Skip to content
Extraits de code Groupes Projets
Valider 2147d0e8 rédigé par Mélanie Colasse's avatar Mélanie Colasse
Parcourir les fichiers

Upload New File

parent 3bda66e0
Aucune branche associée trouvée
Aucune étiquette associée trouvée
Aucune requête de fusion associée trouvée
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <string.h>
#include <semaphore.h>
#include <pthread.h>
#include <limits.h>
#include <time.h>
#include "main.h"
#define NTYPE unsigned long long
#define NTYPE_POURCENT "%llu"
#define LIMITE pow(10,19)
/*
long unsigned : "%lu"
long long lli
unsigned long long llu
...*/
/*
FAIRE :
- faudrait véirifier qu'on a jamais 2 fois le même nombre dans l'algo final (et que tous les nombres y sont)
- combien de threads faut-il prendre par défaut ?
- actuellement si on a un très grands nombres, il va prendre tout le temps et une mémoire énorme pcq on travaille sur un thread par nombre
à mon avis on va devoir faire du multi-thread par nombre
ou au moins réduire sensiblement la quantité de ram qu'on demande pcq elle est beaucoup trop gande il me semble
==============================================================================
QUESTIONS:
- tests pour les autres fonctions, avec le prinf ds l'output
- est-ce que Jenkins doit être bloquant au niveau des push ? => on a le choix
- le README
- fonctionnement en sigle-thread à vérif, faire des tests sur le code avec plusiers ?
- déterminer le nombre de thread à utiliser si on a le choix
- pas nécessaires mais éviter le crash => OK
- enlever les anti-erreurs
- véirif pass test sur ingi
- curseurs de lecture au début des fichiers?
- pourquoi mutex dans la fct_file_out?
*/
//////////////////////////////////////////////////////////////////////////////////////////////////////
//STRUCTURES
//pour un nombre number
typedef struct outputstruct{
NTYPE number;
int number_div; //le nombre de diviseurs de number
NTYPE *tab_div; //le pointeur vers le tableau qui contiendra les diviseurs premiers de number
} outputstruct_t;
//pour stocker les buffers
typedef struct buffers{
NTYPE *buf_1; //buffer des nombres de l'input, rempli par la fonction fct_file_in et lu par la fonction fct_calcul
outputstruct_t **buf_2; //buffer des structures de chaque nombre, rempli par fct_calcul et lu par fct_file_out
} buffers_t;
// FONCTIONS
/* tout ceci est dans le fichier .h
NTYPE *prime_divs( NTYPE*, NTYPE);
void *fct_calcul( void*);
void *fct_file_in( void*);
void *fct_file_out( void*);
*/
////////////////////////////////////////////////////////////////////////////////////////////////////
//FILES
FILE* file_in;
FILE* file_out;
//////////////////////////////////////////////////////////////////////////////////////////////////////
//SEMAPHORES ET MUTEX
pthread_mutex_t mutex_buffer_1; // mutex pour les consommateurs de buffer 1
sem_t empty_1; // sémaphore pour le buffer 1, pour déterminer quand le buffer 1 est vide
sem_t full_1; // idem, pour déterminer quand le buffer 1 est plein
int index_remplissage_1 =0; // pas thread-safe pcq un seul thread qui le modif (producer)
int index_vidage_1 =0; // doit être thread-safe pcq plusieurs threads qui calculent (consumer)
pthread_mutex_t mutex_buffer_2; // mutex pour les producteurs de buffer 2
sem_t empty_2; // sémaphore pour le buffer 2, pour déterminer quand le buffer 2 est vide
sem_t full_2; // sémaphore pour le buffer 2, pour déterminer quand le buffer 2 est vide
int index_remplissage_2 =0; // pas thread-safe pcq un seul thread qui le modif (producer)
int index_vidage_2 =0; // doit être thread-safe pcq plusieurs threads qui calculent (consumer)
int size1; // taille de buffer 1 et de buffer 2
int n_threads;
int main(int argc, char** argv){
fprintf(stdout,"types actuels:");fprintf(stdout,"%s",NTYPE_POURCENT);
////////////////////////////////////////////////////////////////////////////////////////
//GESTION DES ARGUMENTS DONNÉS À LA MAIN
if(argc != 3 && argc != 5){ fprintf(stderr,"not right amount of arguments\n"); return -1; }
//CASE [ prog_name file1 file2 ]
if(argc == 3){
n_threads = 3;// nombre le plus intéressant à déterminer
//open
if( (file_in =fopen(argv[1],"r" )) == NULL ){ fprintf(stderr,"error in open file_in\n"); }
if( (file_out=fopen(argv[2],"w" )) == NULL ){ fprintf(stderr,"error in open file_out\n"); }//écrit dans le file, elle crée si besoin
}
//CASE [ prog_name -N n_threads file1 file2 ]
else{
if( (argv[1][0] != '-') || (argv[1][1] != 'N') ){ fprintf(stderr,"not right amount of arguments\n"); return -1;}
n_threads = atoi(argv[2]); // *(((int*)(* argv) + 3));
//open
if( (file_in =fopen(argv[3],"r" )) == NULL ){ fprintf(stderr,"error in open file_in\n"); }
if( (file_out=fopen(argv[4],"w" )) == NULL ){ fprintf(stderr,"error in open file_out\n"); }//écrit dans le file, elle crée si besoin
}
// placer les curseurs de lecture des fichiers au début de ces derniers
if( fseek(file_in , 0, SEEK_SET) != 0){ fprintf(stderr,"error dans la fct seek in\n"); }
if( fseek(file_out, 0, SEEK_SET) != 0){ fprintf(stderr,"error dans la fct seek out\n"); }
//////////////////////////////////////////////////////////////////////////////////////////////
//INITIALISATIONS
//mutex
if(pthread_mutex_init( &mutex_buffer_2, NULL) !=0){ fprintf(stderr,"error in m utex init de buffer 2\n"); }
if(pthread_mutex_init( &mutex_buffer_1, NULL) !=0){ fprintf(stderr,"error in m utex init de buffer 1\n"); }
//buffers 1,2
size1 = 2*n_threads;
NTYPE* buffer_1 =(NTYPE*) malloc(sizeof(NTYPE )*size1);
outputstruct_t** buffer_2 =(outputstruct_t**) malloc(sizeof(outputstruct_t* )*size1);
if(buffer_1 == NULL){ fprintf(stderr,"erreur dans le malloc de buffer_1\n"); }
if(buffer_2 == NULL){ fprintf(stderr,"erreur dans le malloc de buffer_2\n"); }
//structures outputstruct_t dans le buffer 2
for (int p=0; p<size1;p++){
buffer_2[p]= ( outputstruct_t* ) malloc(sizeof(outputstruct_t));
}
//structure buffer_t
buffers_t *buffers = (buffers_t*) malloc(sizeof(buffers_t));
buffers->buf_1 = buffer_1;
buffers->buf_2 = buffer_2;
//sémaphores
if(sem_init(&empty_1 , 0 , size1) != 0){ fprintf(stderr,"erreur dans le sem_init empty_1\n" );}
if(sem_init(&full_1 , 0 , 0 ) != 0){ fprintf(stderr,"erreur dans le sem_init full_1 \n" );}
if(sem_init(&empty_2 , 0 , size1) != 0){ fprintf(stderr,"erreur dans le sem_init empty_2\n" );}
if(sem_init(&full_2 , 0 , 0 ) != 0){ fprintf(stderr,"erreur dans le sem_init full_2 \n" );}
//threads
pthread_t threads[n_threads];
pthread_t thread_ecriture;
pthread_t thread_lecture;
///////////////////////////////////////////////////////////////////////////////////////////////
//ON MET LES THREADS AU TRAVAIL
if (pthread_create(&thread_ecriture,NULL,&fct_file_out ,(void*) buffers) != 0 ){ fprintf(stderr,"erreur create thread ecriture\n"); }
if (pthread_create(&thread_lecture, NULL,&fct_file_in ,(void*) buffers) != 0 ){ fprintf(stderr,"erreur create thread lecture\n"); }
for (int i=0; i<n_threads; i++){
if (pthread_create(&(threads[i]),NULL, &fct_calcul , (void*)buffers) != 0){ fprintf(stderr,"erreur create_thread[%d]\n",i); }
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/*
- JOIN des threads,
- DESTROY des mutex
- DESTROY des sémaphores
- FREE des données
- CLOSE des files
*/
if (pthread_join(thread_lecture, NULL) != 0) { fprintf(stderr,"erreur dans appel à pthread_join_lecture\n"); }
for( int j = 0; j <n_threads ; j++){
if( pthread_join(threads[j],NULL ) != 0){ fprintf(stderr,"erreur dans appel à pthread_join_calculs\n"); }
}
if (pthread_join(thread_ecriture, NULL) != 0) { fprintf(stderr,"erreur dans appel à pthread_join_ecriture\n"); }
if(sem_destroy(&empty_1)!=0){ fprintf(stderr,"erreur dans sem destroy empty1 \n"); }
if(sem_destroy(&full_1 )!=0){ fprintf(stderr,"erreur dans sem destroy full1 \n"); }
if(sem_destroy(&empty_2)!=0){ fprintf(stderr,"erreur dans sem destroy empty2 \n"); }
if(sem_destroy(&full_2 )!=0){ fprintf(stderr,"erreur dans sem destroy full2 \n"); }
if(pthread_mutex_destroy(&mutex_buffer_1)!=0){ fprintf(stderr,"erreur dans sem destroy empty1\n"); }
if(pthread_mutex_destroy(&mutex_buffer_2)!=0){ fprintf(stderr,"erreur dans sem destroy full1\n" ); }
for (int b=0;b<size1;b++){ free(buffer_2[b]); }
free(buffer_1); free(buffer_2); free(buffers);
fclose(file_in); fclose(file_out); fprintf(stderr,"fin du programme, exit normal O(∩_∩)O\n");
}//fin de la main
//la fonction suivante est dans le fichier prime_divs.c
/*
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// FCT DE CALCUL DES N PREMIERS (POUR UN NUMBER DONNE)
NTYPE * prime_divs (NTYPE *diviseur, NTYPE number){
NTYPE fix_number = number;
NTYPE i, j;
NTYPE a = ceil(sqrt(number));
*diviseur = 0;
// on a une légère perte de mémoire vu qu'on utilise pas le 0 et le 1 dans les array on pourrais ganger en taille
//NTYPE clk_tck = CLOCKS_PER_SEC;
//clock_t t1, t2, t3;
//t1 = clock();
char *bitarray = (char*)malloc(sizeof(char) * a);
//INFO: bitset: array de 0 et 1,
//1 => pas un bon nombre (pas premier et ou pas diviseur)
//0 => ok on le prends (ou pas encore calculé)
//exemple pour 35 => bitarray : [0,1,1,1,0,1]
if (bitarray == NULL){ fprintf(stderr, "erreur malloc de prime_divs\n"); }
memset(bitarray, 0, a);
// comment faire pour que le nombre lui-même ne soit pas compté dans les diviseurs
//t2 = clock();
i = 2;
//NTYPE variable = 1;
//changer le i<a si possible
while (number > 1 && i<a+1) {
//CASE: pour les nombres qui 0 (sont premiers mais pas forcément diviseurs)
if (!bitarray[i]){
//tous les mult de i (sauf i lui-même) à 1 pcq se sont PAS des nombres premiers
for(j = 2*i; j < a; j += i){ if (!bitarray[j]){ bitarray[j] = 1; } }
//SWITCH on sait que i est nombre premier => est-il un diviseur ?
//CASE oui => les nombres premiers qu'il reste à identifier sont les diviseurs premiers de number/i
// (divisés par i autant de fois que nécessaire pour
// - éviter les redondances de calcul
// - trouver plus aisément le dernier nombre premier)
if ((number % i) == 0){
//printf("%llu ", i);
//variable*=i;
(*diviseur)++;
number /= i;
while(number % i == 0){ number /= i;
//variable*=i;
}
//CASE non => on met à 1 pour dire pas compté après
}else{ bitarray[i]=1; }
}
i++;
}
//t3 = clock();
//printf("tout le code prend : %lf ", (t3-t1)/clk_tck);
//printf("bitarray prend : %lf ", (t2-t1)/clk_tck);
NTYPE* prime_dividers;
if(( prime_dividers= (NTYPE*) malloc(sizeof(NTYPE)*((*diviseur)+1) ) )==NULL){ fprintf(stderr,"erreur dans le malloc de prime_divs\n"); }
//Remplir prime_dividers avec les nombres premiers, diviseurs de number
NTYPE k = 0;// nombre de diviseurs => PQ pas utiliser diviseurs lui-même ?
NTYPE m;
for(m = 2; m < i; m++) {
// on add à prime_dividers le nombres dont l'indice vaut 0 dans le bitset
if(!bitarray[m] && (fix_number != 2) ) {
//printf(NTYPE_POURCENT, m);
prime_dividers[k] = m;
k++;
}
}
if (fix_number == 2){
(*diviseur)--;
// ajoute le denier nombre dans la liste de diviseurs dans un cas particulier de l'algo (à détailler)
}if (number != 1 && (number != fix_number)) {
prime_dividers[k] = number;
(*diviseur)++;
//printf("\n");
}
free(bitarray);
return prime_dividers;
}
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// FONCTION DE LA THREAD DE LECTURE
void* fct_file_in(void* buffs){
//BUT: lecture de l'input et remplissage du buffer_1 de buffs par le thread de lecture
///////////////////////////////////////////////////////////////////////////////////////////////////
//PRODUCER BUFFER 1
//DONNEES
buffers_t *buffers = (buffers_t *) buffs;
NTYPE* buffer_1 = buffers->buf_1;
int eof = 0; // eof étant le return de fscan est soit le nombre de int détectés soit EOF
int caractere = 0; //pour gérer un cas particulier
NTYPE input_number; // contiendra le nombre lu
//CODE
//avec prise en compte des caractères spéciaux dans l'input
while (eof != EOF){
// RAPPEL: fscan met le curseur de lecture avant le caractère qu'il n'a pas su lire (un string alors qu'il devait lire un int par ex)
// RAPPEL: fgetc lit le caractère et met le curseur de lecture après le caractère
//gère le cas où on a un nombre négatif
char nana; //contiendra le premier caractere d'une ligne du fichier input
fscanf(file_in,"%c",&nana);
if(nana == '-'){ while( fgetc(file_in) !='\n'){}
}else{ fseek(file_in,-1,SEEK_CUR);}
//lit le nombre
eof = fscanf(file_in, NTYPE_POURCENT, &input_number);
//ne prend pas en compte les nombres plus grand que LIMITE (car code non fonctionnel pour ceux-là)
if (input_number > LIMITE){
continue;
}
//CASE: fin de lecture de l'input => remplissage de buffer 1 avec n_threads "1" pour lui indiquer que fin de lecture
if (eof == EOF){
for(int i =0; i< n_threads; i++){
if(sem_wait(&empty_1)!=0){ fprintf(stderr,"erreur dans le sem wait empty_1 in read fct\n"); }
buffer_1[index_remplissage_1] = 1;
index_remplissage_1++;
index_remplissage_1 %= size1;
if(sem_post(&full_1) != 0){ fprintf(stderr,"erreur dans le sem post full_1 in read fct\n" ); }
}
continue; //à la prochaine itération, on est sûr de sortir
}
//CASE: pas bon format (caractères spéciaux dans la ligne)
if( (eof != 1) ){ while( fgetc(file_in) !='\n'){} }
//CASE: "int\n" bon format et nombre plus grand que 2
//met le nombre dans le buffer 1
else if( (input_number >= 2) && (caractere=fgetc(file_in))=='\n'){
if(sem_wait(&empty_1)!=0){ fprintf(stderr,"erreur dans le sem wait empty_1 in read fct\n"); }
buffer_1[index_remplissage_1] = input_number;
index_remplissage_1++;
index_remplissage_1 %= size1;
if(sem_post(&full_1) != 0){ fprintf(stderr,"erreur dans le sem post full_1 in read fct\n" ); }
}
/*
reste encore un cas particulier, si la ligne de l'input est :
4-2\n
*/
//CASE: on lit le 4 (fscanf), mais le caractère suivant stocké dans
//caractere n'est pas \n, donc on passe la ligne
else if(caractere != '\n'){
while(fgetc(file_in)!='\n'){}
}
}
return (void*) NULL;
}
//////////////////////////////////////////////////////////////////////////////////////////////////
// FONCTION DES THREADS DE CALCUL
void* fct_calcul(void* buffs){
/* BUT :
1) prend le nombre dans le buffer 1 de buffs
2) appelle prime_divs
3) écrit dans buffer_2 de buffs avec le tableau des nombres premiers remplis
*/
//DONNEES
buffers_t* buffers = (buffers_t*) buffs;
outputstruct_t** buffer_2 = buffers->buf_2;
NTYPE* buffer_1 = buffers->buf_1;
NTYPE nombre;
NTYPE diviseurs[1]; //stockera le nombre de diviseurs de nombre
diviseurs[0] = 0;
NTYPE* array; //contiendra les nombres premiers
//CODE
while(1){
//////////////////////////////////////////////////////////////////////////////////////////
//A. CONSUMER BUFFER 1
int index; // indice auxquel on peut aller prendre le nombre dans buffer_1
//prend le nombre dans le buffer 1
if(sem_wait(&full_1)!=0){ fprintf(stderr,"erreur dans le sem wait full_1 in fct calcul\n"); }
pthread_mutex_lock(&mutex_buffer_1);
index = index_vidage_1;
index_vidage_1++;
index_vidage_1 %= size1;
pthread_mutex_unlock(&mutex_buffer_1);
nombre = buffer_1[index];
if(sem_post(&empty_1) != 0){fprintf(stderr,"erreur dans le sem _post empty_1\n" );}
//CASE number=1: signifie que la lecture de l'input est terminée, donc l'indique dans le buffer 2
if(nombre == 1){
if(sem_wait(&empty_2)!=0){ fprintf(stderr,"erreur dans le sem empty_2 in fct calcul\n"); } // attente d’une place libre
pthread_mutex_lock(&mutex_buffer_2);
buffer_2[index_remplissage_2]->number = 1;
buffer_2[index_remplissage_2]->number_div = 1;
buffer_2[index_remplissage_2]->tab_div = NULL;
index_remplissage_2++;
(index_remplissage_2) %= size1;
pthread_mutex_unlock(&mutex_buffer_2);
if(sem_post(&full_2) != 0){ fprintf(stderr,"erreur dans le sem _post full_2\n" ); }
break;
}
//////////////////////////////////////////////////////////////////////////
//B. CALCUL
//appel de prime_divs pour remplir le tableau des diviseurs premiers de nombre
array = prime_divs(diviseurs, nombre);
/////////////////////////////////////////////////////////////////////////////////////////
//C. PRODUCER BUFFER 2
//remplit le buffer 2 avec la structure complétée pour le nombre
if(sem_wait(&empty_2)!=0){ fprintf(stderr,"erreur dans le sem empty_2 in fct calcul\n"); } // attente d’une place libre
pthread_mutex_lock(&mutex_buffer_2);
//(le tableau précédent à déjà été free, PAS la structure,cfr thread fct_file_out)
buffer_2[index_remplissage_2]->number = nombre;
buffer_2[index_remplissage_2]->number_div = *diviseurs;
buffer_2[index_remplissage_2]->tab_div = array;
index_remplissage_2++;
(index_remplissage_2) %= size1;
pthread_mutex_unlock(&mutex_buffer_2);
if(sem_post(&full_2) != 0){ fprintf(stderr,"erreur dans le sem _post full_2\n" ); }
}
return (void*) NULL;
}
//////////////////////////////////////////////////////////////////////////////////////////////////
// FONCTION DE LA THREAD D'ECRITURE
void* fct_file_out(void* buffs){
//BUT: prend les structures dans buffer_2 de buffs et écrit dans l'output
////////////////////////////////////////////////////////////////////////////////////////
// CONSUMER BUFFER 2
//DONNEES
buffers_t* buffers = (buffers_t *) buffs;
outputstruct_t** buffer_2 = buffers->buf_2;
//CODE
int n_moinsun = 0; //pour gérer la fin de la boucle while
while (n_moinsun < n_threads ){
if(sem_wait(&full_2)!=0){ fprintf(stderr,"erreur dans le sem wait in fct calcul\n"); } // attente d’une place remplie
//pthread_mutex_lock(&mutex_buffer_2);
//écrit dans l'output si ce n'est pas fini
if(buffer_2[index_vidage_2]->number != 1){
fprintf(file_out,NTYPE_POURCENT,buffer_2[index_vidage_2]->number);
for( int i=0; i < buffer_2[index_vidage_2]->number_div ; i++){// number->div est utile ici
fprintf(file_out," ");
fprintf(file_out,NTYPE_POURCENT, (buffer_2[index_vidage_2]->tab_div)[i] );
}
fprintf(file_out,"\n");
//CASE : il n'y a plus de structures à écrire dans l'output
//pour le signaler, incrémente n_moinsun; lorsque toutes les threads
//sont passées par là, la boucle s'arrête
}else{ n_moinsun++; }
// pas besoin pcq index_vidage n'est utilisé que par la fct file_out
//pthread_mutex_lock(&mutex_buffer_2);
free(buffer_2[index_vidage_2]->tab_div);//on free le pointeur de l'ancien tableau de nombres premiers de la struct
//pthread_mutex_unlock(&mutex_buffer_2);
index_vidage_2++;
index_vidage_2 %= size1;
//pthread_mutex_unlock(&mutex_buffer_2);
if(sem_post(&empty_2) != 0){ fprintf(stderr,"erreur dans le sem _post empty_2\n" ); }
}
return (void*) NULL;
}
0% Chargement en cours ou .
You are about to add 0 people to the discussion. Proceed with caution.
Terminez d'abord l'édition de ce message.
Veuillez vous inscrire ou vous pour commenter