Importation du code depuis GitHub
This commit is contained in:
commit
05476b94ad
13 changed files with 1080 additions and 0 deletions
10
README.md
Normal file
10
README.md
Normal file
|
|
@ -0,0 +1,10 @@
|
||||||
|
# Cours de programmation système & multi-threading (I4IRTR11)
|
||||||
|
Partage de mes TD et TP de programmation système & multi-threading effectués lors de mon S6 à l'INSA de Toulouse.
|
||||||
|
|
||||||
|
## Liste des TD validés à présent :
|
||||||
|
* TD1
|
||||||
|
* TD2
|
||||||
|
* TD3
|
||||||
|
* TD4
|
||||||
|
* TD5
|
||||||
|
* TD6 - mais on peut mieux faire
|
||||||
33
TD/TD1/main.c
Normal file
33
TD/TD1/main.c
Normal file
|
|
@ -0,0 +1,33 @@
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <pthread.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
|
||||||
|
void * fn_thread (void * p_int) {
|
||||||
|
for (int i = 0; i < *(int *) p_int; ++i) {
|
||||||
|
printf("et mon courroux\n");
|
||||||
|
sleep(1);
|
||||||
|
}
|
||||||
|
pthread_exit(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
int main () {
|
||||||
|
int M = 0;
|
||||||
|
int N = 0;
|
||||||
|
pthread_t p1;
|
||||||
|
|
||||||
|
printf("Saisir M puis N : \n");
|
||||||
|
scanf ("%d", &M);
|
||||||
|
scanf ("%d", &N);
|
||||||
|
printf("Ok ! \n");
|
||||||
|
|
||||||
|
pthread_create (& p1, NULL, fn_thread, (void *) &N);
|
||||||
|
for (int i = 0; i < M; ++i) {
|
||||||
|
printf("Coucou\n");
|
||||||
|
sleep(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
pthread_join(p1, NULL);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
41
TD/TD2/main.c
Normal file
41
TD/TD2/main.c
Normal file
|
|
@ -0,0 +1,41 @@
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <pthread.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
double * px = NULL;
|
||||||
|
|
||||||
|
static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
|
||||||
|
|
||||||
|
void * fn_thread (void * p_int) {
|
||||||
|
for (int i = 0; i < *(int *) p_int; ++i) {
|
||||||
|
pthread_mutex_lock(& mutex);
|
||||||
|
printf("%f\n", *px);
|
||||||
|
pthread_mutex_unlock(& mutex);
|
||||||
|
}
|
||||||
|
pthread_exit(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
int main () {
|
||||||
|
int max = 0;
|
||||||
|
pthread_t p1;
|
||||||
|
|
||||||
|
printf("Saisir max : \n");
|
||||||
|
scanf ("%d", &max);
|
||||||
|
printf("Ok ! \n");
|
||||||
|
|
||||||
|
double x = 1.0;
|
||||||
|
px = &x;
|
||||||
|
pthread_create (& p1, NULL, fn_thread, (void *) &max);
|
||||||
|
|
||||||
|
for (int i = 0; i < max; ++i) {
|
||||||
|
pthread_mutex_lock(& mutex);
|
||||||
|
px = NULL;
|
||||||
|
printf("i : %d\n", i);
|
||||||
|
px = &x;
|
||||||
|
pthread_mutex_unlock(& mutex);
|
||||||
|
}
|
||||||
|
|
||||||
|
pthread_join(p1, NULL);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
68
TD/TD3/main.c
Normal file
68
TD/TD3/main.c
Normal file
|
|
@ -0,0 +1,68 @@
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <pthread.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
// Ressources disponible
|
||||||
|
int M = 4;
|
||||||
|
|
||||||
|
// Mutex
|
||||||
|
static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
|
||||||
|
pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
|
||||||
|
|
||||||
|
void prendre_ressource(int rsc){
|
||||||
|
if (pthread_mutex_lock(&mutex))
|
||||||
|
exit(-1);
|
||||||
|
|
||||||
|
while (rsc > M)
|
||||||
|
pthread_cond_wait(&cond, &mutex);
|
||||||
|
|
||||||
|
if (M - rsc >= 0)
|
||||||
|
M -= rsc;
|
||||||
|
else
|
||||||
|
exit(1);
|
||||||
|
|
||||||
|
pthread_mutex_unlock(&mutex);
|
||||||
|
}
|
||||||
|
|
||||||
|
void liberer_ressource(int rsc){
|
||||||
|
if (pthread_mutex_lock(&mutex))
|
||||||
|
exit(-1);
|
||||||
|
|
||||||
|
M += rsc;
|
||||||
|
|
||||||
|
pthread_cond_broadcast(&cond);
|
||||||
|
pthread_mutex_unlock(&mutex);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void * fn_thread (void * p_int) {
|
||||||
|
int rsc = *(int *) p_int;
|
||||||
|
printf("Thread en attente pour %d ressource(s)...\n", rsc);
|
||||||
|
prendre_ressource(rsc);
|
||||||
|
printf("Thread a pris %d ressource(s)...\n", rsc);
|
||||||
|
sleep(rsc);
|
||||||
|
printf("%d ressource(s) utilisée(s) et rendue(s)...\n", rsc);
|
||||||
|
liberer_ressource(rsc);
|
||||||
|
printf("Thread (à %d rsc) fini...\n", rsc);
|
||||||
|
pthread_exit(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
int main () {
|
||||||
|
pthread_t p1;
|
||||||
|
pthread_t p2;
|
||||||
|
pthread_t p3;
|
||||||
|
int rsc1 = 3;
|
||||||
|
int rsc2 = 2;
|
||||||
|
int rsc3 = 1;
|
||||||
|
|
||||||
|
pthread_create (& p1, NULL, fn_thread, (void *) &rsc1);
|
||||||
|
pthread_create (& p2, NULL, fn_thread, (void *) &rsc2);
|
||||||
|
pthread_create (& p3, NULL, fn_thread, (void *) &rsc3);
|
||||||
|
|
||||||
|
pthread_join(p1, NULL);
|
||||||
|
pthread_join(p2, NULL);
|
||||||
|
pthread_join(p3, NULL);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
50
TD/TD4/main.c
Normal file
50
TD/TD4/main.c
Normal file
|
|
@ -0,0 +1,50 @@
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <pthread.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
// Ressources disponible
|
||||||
|
int N = 3;
|
||||||
|
|
||||||
|
// Once
|
||||||
|
pthread_once_t once = PTHREAD_ONCE_INIT;
|
||||||
|
pthread_key_t key;
|
||||||
|
|
||||||
|
int incrementation() {
|
||||||
|
int *s_int;
|
||||||
|
s_int = (int*)pthread_getspecific(key);
|
||||||
|
return ++(*s_int);
|
||||||
|
}
|
||||||
|
|
||||||
|
void fonction_init() {
|
||||||
|
printf("Initialisation...\n");
|
||||||
|
pthread_key_create(&key, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
void * fn_thread (void * n) {
|
||||||
|
pthread_once(&once, fonction_init);
|
||||||
|
|
||||||
|
int* s_int;
|
||||||
|
s_int = malloc(sizeof(int));
|
||||||
|
*s_int = pthread_self();
|
||||||
|
pthread_setspecific(key, (void *)s_int);
|
||||||
|
|
||||||
|
for (int i = 0; i < N; ++i){
|
||||||
|
printf("Boucle : %d\n", incrementation());
|
||||||
|
}
|
||||||
|
pthread_exit(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
int main () {
|
||||||
|
pthread_t p1;
|
||||||
|
pthread_t p2;
|
||||||
|
|
||||||
|
pthread_create (& p1, NULL, fn_thread, NULL);
|
||||||
|
pthread_create (& p2, NULL, fn_thread, NULL);
|
||||||
|
fn_thread(NULL);
|
||||||
|
|
||||||
|
pthread_join(p1, NULL);
|
||||||
|
pthread_join(p2, NULL);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
47
TD/TD5/main.c
Normal file
47
TD/TD5/main.c
Normal file
|
|
@ -0,0 +1,47 @@
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <pthread.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
#define max 6
|
||||||
|
|
||||||
|
static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
|
||||||
|
|
||||||
|
|
||||||
|
void unlock(){
|
||||||
|
pthread_mutex_unlock(& mutex);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void * fn_thread (void * n) {
|
||||||
|
pthread_mutex_lock(& mutex);
|
||||||
|
printf("[THREAD] J'ai le mutex.\n");
|
||||||
|
|
||||||
|
for (int i = 0; i < max; ++i){
|
||||||
|
printf("[THREAD] tid: %ld\n", pthread_self());
|
||||||
|
sleep(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
pthread_mutex_unlock(& mutex);
|
||||||
|
|
||||||
|
pthread_exit(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int main () {
|
||||||
|
pthread_t p1;
|
||||||
|
|
||||||
|
for (int i = 0; i < 2; ++i){
|
||||||
|
pthread_create (& p1, NULL, fn_thread, NULL);
|
||||||
|
pthread_cleanup_push( &unlock, NULL );
|
||||||
|
|
||||||
|
for (int i = 0; i < max/2; ++i){
|
||||||
|
printf("[MAIN] pid: %d\n", getpid());
|
||||||
|
sleep(1);
|
||||||
|
}
|
||||||
|
pthread_cancel(p1);
|
||||||
|
pthread_cleanup_pop(1);
|
||||||
|
sleep(1);
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
66
TD/TD5/sig.c
Normal file
66
TD/TD5/sig.c
Normal file
|
|
@ -0,0 +1,66 @@
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <pthread.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <signal.h>
|
||||||
|
|
||||||
|
#define max 6
|
||||||
|
|
||||||
|
void handler_sigusr1(int sig) {
|
||||||
|
printf("PID %d a reçu un SIGUSR1 : %d\n", getpid(), sig);
|
||||||
|
}
|
||||||
|
|
||||||
|
void handler_sigusr2(int sig) {
|
||||||
|
printf("PID %d a reçu un SIGUSR2 : %d\n", getpid(), sig);
|
||||||
|
exit(2);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void * fn_thread (void * n) {
|
||||||
|
|
||||||
|
// Masque tous les signaux sauf SIGUSR1
|
||||||
|
sigset_t ens_signal;
|
||||||
|
sigfillset(&ens_signal);
|
||||||
|
sigdelset(&ens_signal,SIGUSR1);
|
||||||
|
sigprocmask(SIG_SETMASK, &ens_signal,NULL);
|
||||||
|
|
||||||
|
while (1){
|
||||||
|
printf("THREAD up and running.\n");
|
||||||
|
sleep(1);
|
||||||
|
}
|
||||||
|
pthread_exit(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int main () {
|
||||||
|
printf("Entry.\n");
|
||||||
|
|
||||||
|
// Configuration des signaux
|
||||||
|
struct sigaction action;
|
||||||
|
struct sigaction action2;
|
||||||
|
action.sa_handler = handler_sigusr1;
|
||||||
|
action2.sa_handler = handler_sigusr2;
|
||||||
|
|
||||||
|
if (sigaction(SIGUSR1, &action, NULL) || sigaction(SIGUSR2, &action2, NULL)) {
|
||||||
|
printf("Erreur handler (SIGUSR1).\n");
|
||||||
|
exit(-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Création du thread
|
||||||
|
pthread_t p1;
|
||||||
|
pthread_create (& p1, NULL, fn_thread, NULL);
|
||||||
|
|
||||||
|
// Masque tous les signaux sauf SIGUSR2
|
||||||
|
sigset_t ens_signal;
|
||||||
|
sigfillset(&ens_signal);
|
||||||
|
sigdelset(&ens_signal,SIGUSR2);
|
||||||
|
sigprocmask(SIG_SETMASK, &ens_signal,NULL);
|
||||||
|
|
||||||
|
while (1){
|
||||||
|
printf("MAIN up and running (pid: %d).\n", getpid());
|
||||||
|
sleep(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
77
TD/TD6/main.c
Normal file
77
TD/TD6/main.c
Normal file
|
|
@ -0,0 +1,77 @@
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <pthread.h>
|
||||||
|
#include <sys/time.h>
|
||||||
|
|
||||||
|
#define NB_THREAD 4
|
||||||
|
#define F 10000000
|
||||||
|
|
||||||
|
// Nombre de point à l'intérieur du cercle
|
||||||
|
int retvals[NB_THREAD];
|
||||||
|
int t_num = 0;
|
||||||
|
|
||||||
|
|
||||||
|
/// Fonction de calcul en thread
|
||||||
|
void * fn_thread (void * p_int) {
|
||||||
|
// Le thread récupère un numéro
|
||||||
|
int num = t_num;
|
||||||
|
++t_num;
|
||||||
|
long double x, y;
|
||||||
|
int fn = F/NB_THREAD;
|
||||||
|
int in = 0;
|
||||||
|
|
||||||
|
for (int i = 0; i < fn; ++i) {
|
||||||
|
// On tire aléatoirement x et y entre -1 et 1
|
||||||
|
x = (long double)rand()/(long double)(RAND_MAX);
|
||||||
|
y = (long double)rand()/(long double)(RAND_MAX);
|
||||||
|
|
||||||
|
if ((x*x) + (y*y) <= 1.0)
|
||||||
|
++in;
|
||||||
|
}
|
||||||
|
retvals[num] = in;
|
||||||
|
pthread_exit(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
int main () {
|
||||||
|
pthread_t threads[NB_THREAD];
|
||||||
|
|
||||||
|
// Graine aléatoire avec le temps
|
||||||
|
srand(time(NULL));
|
||||||
|
|
||||||
|
// Outils pour le chronometre
|
||||||
|
struct timeval begin, end;
|
||||||
|
gettimeofday(&begin, NULL);
|
||||||
|
|
||||||
|
// Lancement des threads
|
||||||
|
for (int j = 0; j < NB_THREAD; ++j) {
|
||||||
|
if (pthread_create(&threads[j], NULL, fn_thread, NULL) != 0) {
|
||||||
|
fprintf(stderr, "Cannot create thread # %d\n", j);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Joining threads
|
||||||
|
for (int i = 0; i < NB_THREAD; ++i) {
|
||||||
|
pthread_join(threads[i], NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
//Summing all "in" points
|
||||||
|
int in = 0;
|
||||||
|
for (int i = 0; i < NB_THREAD; ++i) {
|
||||||
|
in += retvals[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Calculing pi
|
||||||
|
long double pi = ((long double) in * 4.0) / (long double) F;
|
||||||
|
|
||||||
|
// Stopping timer
|
||||||
|
gettimeofday(&end, NULL);
|
||||||
|
|
||||||
|
//printf("Ratio inside / outside : %d/%d\n", in, F - in);
|
||||||
|
printf("Valeur calculée de pi : %Lf\n", pi);
|
||||||
|
printf("Nombre de thread : %d\n", NB_THREAD);
|
||||||
|
printf("Nombre de point : %d\n", F);
|
||||||
|
printf("Time: %ld microseconds\n", ((end.tv_sec - begin.tv_sec)*1000000L + end.tv_usec) - begin.tv_usec);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
98
TP/TP1/main.c
Normal file
98
TP/TP1/main.c
Normal file
|
|
@ -0,0 +1,98 @@
|
||||||
|
#include <signal.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <sys/time.h>
|
||||||
|
|
||||||
|
#define NB_ITR 100000
|
||||||
|
|
||||||
|
void handler_sigusr1(int sig) {
|
||||||
|
printf("PID %d a reçu un SIGUSR1 : %d\n", getpid(), sig);
|
||||||
|
exit(2);
|
||||||
|
}
|
||||||
|
|
||||||
|
void handler_sigchld(int sig) {
|
||||||
|
printf("PID %d a reçu un SIGCHLD : %d\n", getpid(), sig);
|
||||||
|
printf("Le fils est mort...\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
int main() {
|
||||||
|
// Variables fork
|
||||||
|
int pid = 0;
|
||||||
|
|
||||||
|
// Variables gestion des signaux
|
||||||
|
struct sigaction action;
|
||||||
|
struct sigaction action2;
|
||||||
|
action.sa_handler = handler_sigusr1;
|
||||||
|
action2.sa_handler = handler_sigchld;
|
||||||
|
|
||||||
|
// Variables tubes
|
||||||
|
int p1[2];
|
||||||
|
int p2[2];
|
||||||
|
int tsfr = 0;
|
||||||
|
int tsfr2 = 0;
|
||||||
|
|
||||||
|
// Outils pour le chronometre
|
||||||
|
struct timeval begin, end;
|
||||||
|
|
||||||
|
// Initialisation des signaux
|
||||||
|
if (sigaction(SIGUSR1, &action, NULL)) {
|
||||||
|
printf("Erreur handler (SIGUSR1).\n");
|
||||||
|
exit(-1);
|
||||||
|
}
|
||||||
|
if (sigaction(SIGCHLD, &action2, NULL)) {
|
||||||
|
printf("Erreur handler (SIGCHLD).\n");
|
||||||
|
exit(-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Initialisation des tubes
|
||||||
|
if (pipe(p1) || pipe(p2)) {
|
||||||
|
printf("Erreur pipe.\n");
|
||||||
|
exit(-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fork
|
||||||
|
switch (pid = fork()) {
|
||||||
|
case -1:
|
||||||
|
printf("Erreur fork.\n");
|
||||||
|
exit(-1);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0:
|
||||||
|
printf("Le fils a correctement démarré (PID %d)\n", getpid());
|
||||||
|
|
||||||
|
// On lit, on incrémente et on renvoie
|
||||||
|
while (1) {
|
||||||
|
read(p1[0], &tsfr2, sizeof(tsfr2));
|
||||||
|
++tsfr2;
|
||||||
|
write(p2[1], &tsfr2, sizeof(tsfr2));
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
printf("Le père est ok (PID %d), le PID du fils est %d\n", getpid(), pid);
|
||||||
|
|
||||||
|
// Comme le fils, mais on chronometre
|
||||||
|
int nb_boucle = 0;
|
||||||
|
gettimeofday(&begin, NULL);
|
||||||
|
while (nb_boucle < NB_ITR) {
|
||||||
|
++tsfr;
|
||||||
|
write(p1[1], &tsfr, sizeof(tsfr));
|
||||||
|
read(p2[0], &tsfr, sizeof(tsfr));
|
||||||
|
nb_boucle++;
|
||||||
|
}
|
||||||
|
gettimeofday(&end, NULL);
|
||||||
|
kill(pid, SIGUSR1);
|
||||||
|
|
||||||
|
// On calcul le débit
|
||||||
|
int delta = ((end.tv_sec - begin.tv_sec)*1000000L + end.tv_usec) - begin.tv_usec;
|
||||||
|
int debit = (nb_boucle*2*sizeof(tsfr2)*8)/(delta); // (delta est déjà en us)
|
||||||
|
|
||||||
|
printf("Débit calculé : %d Mb/s\n", debit);
|
||||||
|
printf("[DEBUG] delta : %d us, tsfr : %d\n", delta, tsfr);
|
||||||
|
|
||||||
|
return debit;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
110
TP/TP1/tube_nomme.c
Normal file
110
TP/TP1/tube_nomme.c
Normal file
|
|
@ -0,0 +1,110 @@
|
||||||
|
#include <signal.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <sys/time.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
|
||||||
|
#define NB_ITR 1000
|
||||||
|
|
||||||
|
void utilisation() {
|
||||||
|
printf("Usage : ./a.out [c] [s]\n");
|
||||||
|
exit(-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
void server() {
|
||||||
|
printf("Server mode (ping only)...\n");
|
||||||
|
|
||||||
|
// Variables tube nommé
|
||||||
|
int d_lect_1, d_ecr_1;
|
||||||
|
int d_lect_2, d_ecr_2;
|
||||||
|
|
||||||
|
printf("Création des tubes...");
|
||||||
|
if (mkfifo("/tmp/tube1", S_IRUSR | S_IWUSR | S_IRGRP)
|
||||||
|
|| mkfifo("/tmp/tube2", S_IRUSR | S_IWUSR | S_IRGRP)) {
|
||||||
|
printf("Erreur tube.\n");
|
||||||
|
exit(-1);
|
||||||
|
}
|
||||||
|
printf("OK\n");
|
||||||
|
|
||||||
|
printf("Ouverture des tubes...");
|
||||||
|
if (!(d_lect_1 = open("/tmp/tube1", O_RDONLY))){
|
||||||
|
printf("Erreur ouverture tube (READ).\n");
|
||||||
|
exit(-1);
|
||||||
|
}
|
||||||
|
printf("OK1...");
|
||||||
|
|
||||||
|
if (!(d_ecr_2 = open("/tmp/tube2", O_WRONLY))){
|
||||||
|
printf("Erreur ouverture tube (WRITE).\n");
|
||||||
|
exit(-1);
|
||||||
|
}
|
||||||
|
printf("OK2\n");
|
||||||
|
|
||||||
|
// On lit, on incrémente et on renvoie
|
||||||
|
int tsfr = 0;
|
||||||
|
while (1) {
|
||||||
|
read(d_lect_1, &tsfr, sizeof(tsfr));
|
||||||
|
++tsfr;
|
||||||
|
write(d_ecr_2, &tsfr, sizeof(tsfr));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void client() {
|
||||||
|
printf("Client mode...\n");
|
||||||
|
|
||||||
|
// Variables tube nommé
|
||||||
|
int d_lect_1, d_ecr_1;
|
||||||
|
int d_lect_2, d_ecr_2;
|
||||||
|
|
||||||
|
printf("Ouverture des tubes...\n");
|
||||||
|
if (!(d_ecr_1 = open("/tmp/tube1", O_WRONLY))){
|
||||||
|
printf("Erreur ouverture tube (WRITE).\n");
|
||||||
|
exit(-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(d_lect_2 = open("/tmp/tube2", O_RDONLY))){
|
||||||
|
printf("Erreur ouverture tube (READ).\n");
|
||||||
|
exit(-1);
|
||||||
|
}
|
||||||
|
printf("Tubes ouverts.\n");
|
||||||
|
|
||||||
|
// Outils pour le chronometre
|
||||||
|
struct timeval begin, end;
|
||||||
|
|
||||||
|
// Ping pong
|
||||||
|
int tsfr = 0;
|
||||||
|
int nb_boucle = 0;
|
||||||
|
printf("Lancement du chronometre.\n");
|
||||||
|
gettimeofday(&begin, NULL);
|
||||||
|
while (nb_boucle < NB_ITR) {
|
||||||
|
++tsfr;
|
||||||
|
write(d_ecr_1, &tsfr, sizeof(tsfr));
|
||||||
|
read(d_lect_2, &tsfr, sizeof(tsfr));
|
||||||
|
nb_boucle++;
|
||||||
|
}
|
||||||
|
gettimeofday(&end, NULL);
|
||||||
|
|
||||||
|
// On calcul le débit
|
||||||
|
int delta =
|
||||||
|
((end.tv_sec - begin.tv_sec) * 1000000L + end.tv_usec) - begin.tv_usec;
|
||||||
|
int debit =
|
||||||
|
(nb_boucle * 2 * sizeof(tsfr) * 8) / (delta); // (delta est déjà en us)
|
||||||
|
|
||||||
|
printf("Débit calculé : %d Mb/s\n", debit);
|
||||||
|
printf("[DEBUG] delta : %d us, tsfr : %d\n", delta, tsfr);
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char **argv) {
|
||||||
|
// Arguments parsing
|
||||||
|
if (argc != 2) {
|
||||||
|
utilisation();
|
||||||
|
}
|
||||||
|
if (*argv[1] == 's') {
|
||||||
|
server();
|
||||||
|
} else if (*argv[1] == 'c') {
|
||||||
|
client();
|
||||||
|
} else {
|
||||||
|
utilisation();
|
||||||
|
}
|
||||||
|
}
|
||||||
111
TP/TP2/main.c
Normal file
111
TP/TP2/main.c
Normal file
|
|
@ -0,0 +1,111 @@
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <sys/ipc.h>
|
||||||
|
#include <sys/sem.h>
|
||||||
|
#include <sys/time.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
#define KEY 30
|
||||||
|
|
||||||
|
/*
|
||||||
|
* TP 2 partie sémaphore OK.
|
||||||
|
* L'exclusion mutuelle est observée correctement.
|
||||||
|
* Lancez d'abord le serveur puis le client.
|
||||||
|
* Si echec, essayez de changer la clé.
|
||||||
|
*/
|
||||||
|
|
||||||
|
void utilisation() {
|
||||||
|
printf("Usage : ./a.out [c] [s]\n");
|
||||||
|
exit(-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
void server() {
|
||||||
|
int key = KEY;
|
||||||
|
int init = 1;
|
||||||
|
char recv[1];
|
||||||
|
struct sembuf op;
|
||||||
|
int sem = semget((key_t)key, 1, 666 | IPC_CREAT);
|
||||||
|
|
||||||
|
if (sem < 0) {
|
||||||
|
printf("Erreur création sémaphore.\n");
|
||||||
|
exit(-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (semctl(sem, 0, SETVAL, init) == -1) {
|
||||||
|
printf("Erreur initialisation sémaphore.\n");
|
||||||
|
exit(-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
op.sem_num = 0;
|
||||||
|
op.sem_flg = 0;
|
||||||
|
|
||||||
|
while (1) {
|
||||||
|
op.sem_op = -1;
|
||||||
|
printf("Serveur en attente...\n");
|
||||||
|
if (semop(sem, &op, 1)) {
|
||||||
|
printf("Erreur attente.\n");
|
||||||
|
exit(-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
printf("Le serveur a la main. Entrez qqc : ");
|
||||||
|
fgets(recv, 10, stdin);
|
||||||
|
|
||||||
|
op.sem_op = 1;
|
||||||
|
printf("Le serveur rend la main.\n");
|
||||||
|
if (semop(sem, &op, 1)) {
|
||||||
|
printf("Erreur op.\n");
|
||||||
|
exit(-1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void client() {
|
||||||
|
int key = KEY;
|
||||||
|
int init = 0;
|
||||||
|
char recv[1];
|
||||||
|
struct sembuf op;
|
||||||
|
int sem = semget((key_t)key, 0, 0);
|
||||||
|
|
||||||
|
if (sem < 0) {
|
||||||
|
printf("Erreur création sémaphore.\n");
|
||||||
|
exit(-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
op.sem_num = 0;
|
||||||
|
op.sem_flg = 0;
|
||||||
|
|
||||||
|
while (1) {
|
||||||
|
op.sem_op = -1;
|
||||||
|
printf("Client en attente...\n");
|
||||||
|
if (semop(sem, &op, 1)) {
|
||||||
|
printf("Erreur attente.\n");
|
||||||
|
exit(-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
printf("Le client a la main. Entrez qqc : ");
|
||||||
|
fgets(recv, 10, stdin);
|
||||||
|
|
||||||
|
op.sem_op = 1;
|
||||||
|
printf("Le client rend la main.\n");
|
||||||
|
if (semop(sem, &op, 1)) {
|
||||||
|
printf("Erreur op.\n");
|
||||||
|
exit(-1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char **argv) {
|
||||||
|
|
||||||
|
// Arguments parsing
|
||||||
|
if (argc != 2) {
|
||||||
|
utilisation();
|
||||||
|
}
|
||||||
|
if (*argv[1] == 's') {
|
||||||
|
server();
|
||||||
|
} else if (*argv[1] == 'c') {
|
||||||
|
client();
|
||||||
|
} else {
|
||||||
|
utilisation();
|
||||||
|
}
|
||||||
|
}
|
||||||
195
TP/TP2/shared_mem.c
Normal file
195
TP/TP2/shared_mem.c
Normal file
|
|
@ -0,0 +1,195 @@
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <sys/ipc.h>
|
||||||
|
#include <sys/sem.h>
|
||||||
|
#include <sys/shm.h>
|
||||||
|
#include <sys/time.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
#define KEY 160
|
||||||
|
#define NB_ITERATION 100000
|
||||||
|
|
||||||
|
/*
|
||||||
|
* TP2 Partie 3 Communication par mémoire partagée
|
||||||
|
* On observe une alternance correct et derterministe.
|
||||||
|
* Le débit calculé est cohérent
|
||||||
|
*/
|
||||||
|
|
||||||
|
void utilisation() {
|
||||||
|
printf("Usage : ./a.out [c] [s]\n");
|
||||||
|
exit(-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char *argv[]) {
|
||||||
|
int server = -1;
|
||||||
|
struct timeval begin, end;
|
||||||
|
|
||||||
|
// Variables SHM
|
||||||
|
int key_shm = KEY;
|
||||||
|
int *shm = NULL;
|
||||||
|
int shmid = 0;
|
||||||
|
|
||||||
|
// Variables IPC
|
||||||
|
int key = KEY;
|
||||||
|
int init_s = 0;
|
||||||
|
int init_c = 1;
|
||||||
|
char recv[1];
|
||||||
|
struct sembuf op;
|
||||||
|
int sem_s, sem_c;
|
||||||
|
|
||||||
|
/* Traitement des arguments */
|
||||||
|
if (argc != 2) {
|
||||||
|
utilisation();
|
||||||
|
}
|
||||||
|
if (*argv[1] == 's') {
|
||||||
|
server = 1;
|
||||||
|
sem_s = semget((key_t)key, 1, 666 | IPC_CREAT);
|
||||||
|
sem_c = semget((key_t)key+1, 1, 666 | IPC_CREAT);
|
||||||
|
} else if (*argv[1] == 'c') {
|
||||||
|
sem_s = semget((key_t)key, 0, 0);
|
||||||
|
sem_c = semget((key_t)key+1, 0, 0);
|
||||||
|
server = 0;
|
||||||
|
} else {
|
||||||
|
utilisation();
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Création du sémaphore */
|
||||||
|
if (sem_s < 0 || sem_c < 0) {
|
||||||
|
printf("Erreur création sémaphore.\n");
|
||||||
|
exit(-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Initialisation du sémaphore */
|
||||||
|
if (server) {
|
||||||
|
if (semctl(sem_s, 0, SETVAL, init_s) == -1 || semctl(sem_c, 0, SETVAL, init_c) == -1) {
|
||||||
|
printf("Erreur initialisation sémaphore.\n");
|
||||||
|
exit(-1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
op.sem_num = 0;
|
||||||
|
op.sem_flg = 0;
|
||||||
|
|
||||||
|
/* Création de la SHM */
|
||||||
|
if (!(shmid = shmget((key_t)key_shm, 4, 0666 | IPC_CREAT))) {
|
||||||
|
printf("Erreur création SHM.\n");
|
||||||
|
exit(-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Attachement de la shm */
|
||||||
|
if (!(shm = (int *)shmat(shmid, 0, 0))) {
|
||||||
|
printf("Erreur attache SHM.\n");
|
||||||
|
exit(-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
////////SERVER////////
|
||||||
|
if (server) {
|
||||||
|
printf("Mode serveur.\n");
|
||||||
|
|
||||||
|
for (int i = 0; i < (NB_ITERATION/2); ++i) {
|
||||||
|
op.sem_op = -1;
|
||||||
|
//printf("Serveur en attente...\n");
|
||||||
|
if (semop(sem_s, &op, 1)) {
|
||||||
|
printf("Erreur attente.\n");
|
||||||
|
exit(-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
//printf("On incrémente le shm...");
|
||||||
|
(*shm)++;
|
||||||
|
//printf("Fait.\n");
|
||||||
|
//sleep(1);
|
||||||
|
|
||||||
|
op.sem_op = 1;
|
||||||
|
//printf("Le serveur rend la main.\n");
|
||||||
|
if (semop(sem_c, &op, 1)) {
|
||||||
|
printf("Erreur op.\n");
|
||||||
|
exit(-1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
////////CLIENT////////
|
||||||
|
else {
|
||||||
|
printf("Mode client.\n");
|
||||||
|
printf("Lancement du chronometre.\n");
|
||||||
|
gettimeofday(&begin, NULL);
|
||||||
|
|
||||||
|
|
||||||
|
for (int i = 0; i < (NB_ITERATION/2); ++i) {
|
||||||
|
op.sem_op = -1;
|
||||||
|
//printf("Client en attente...\n");
|
||||||
|
if (semop(sem_c, &op, 1)) {
|
||||||
|
printf("Erreur attente.\n");
|
||||||
|
exit(-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
//printf("On incrémente le shm...");
|
||||||
|
(*shm)++;
|
||||||
|
//printf("Fait.\n");
|
||||||
|
//sleep(1);
|
||||||
|
|
||||||
|
//printf("Le client rend la main.\n");
|
||||||
|
op.sem_op = 1;
|
||||||
|
if (semop(sem_s, &op, 1)) {
|
||||||
|
printf("Erreur op.\n");
|
||||||
|
exit(-1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
gettimeofday(&end, NULL);
|
||||||
|
op.sem_op = -1;
|
||||||
|
if (semop(sem_c, &op, 1)) {
|
||||||
|
printf("Erreur attente.\n");
|
||||||
|
exit(-1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
printf("Valeur finale SHM : %d\n", *shm);
|
||||||
|
/* detache la SHM */
|
||||||
|
if (shmdt(shm)) {
|
||||||
|
printf("Erreur détachement.\n");
|
||||||
|
exit(-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!server) {
|
||||||
|
/* Destruction SHM */
|
||||||
|
if (shmctl(shmid, IPC_RMID, 0)) {
|
||||||
|
printf("Erreur destruction SHM.\n");
|
||||||
|
exit(-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Libération sémaphore */
|
||||||
|
if (semctl(sem_s, 0, IPC_RMID, 0) || semctl(sem_c, 0, IPC_RMID, 0)) {
|
||||||
|
printf("Erreur libération sémaphore.\n");
|
||||||
|
exit(-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Calcul débit*/
|
||||||
|
int delta =
|
||||||
|
((end.tv_sec - begin.tv_sec) * 1000000L + end.tv_usec) - begin.tv_usec;
|
||||||
|
int debit =
|
||||||
|
(NB_ITERATION * 2 * sizeof(int) * 8) / (delta); // (delta est déjà en us)
|
||||||
|
|
||||||
|
printf("Débit calculé : %d Mb/s\n", debit);
|
||||||
|
}
|
||||||
|
|
||||||
|
printf("Fin.\n");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
if (server) {
|
||||||
|
printf("Affectation de la valeur par le serveur.\n");
|
||||||
|
*shm = 10;
|
||||||
|
|
||||||
|
sleep(10);
|
||||||
|
printf("Nouvelle valeur lue par le serveur : %d\n", *shm);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
printf("Valeur lue par le client : %d\n", *shm);
|
||||||
|
*shm = 28;
|
||||||
|
printf("Valeur modifiée par le client : %d\n", *shm);
|
||||||
|
}
|
||||||
|
|
||||||
|
*/
|
||||||
174
TP/TP3/calcul.c
Normal file
174
TP/TP3/calcul.c
Normal file
|
|
@ -0,0 +1,174 @@
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <sys/time.h>
|
||||||
|
#include <pthread.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
#define D 1000
|
||||||
|
|
||||||
|
/*
|
||||||
|
* TP 3
|
||||||
|
* 1) Fait et ok.
|
||||||
|
* 2) Fait et ok. On constate que la seconde méthode est plus longue.
|
||||||
|
* 3) Ça ne donne pas la bonne valeur : il faut proteger l'incrémentation par un mutex
|
||||||
|
* 4) On constate que le temps de'exécution augmente de manière exp.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
int V[D];
|
||||||
|
int V_plus[D];
|
||||||
|
int A[D][D];
|
||||||
|
int t_num = 0;
|
||||||
|
|
||||||
|
int compt_glob = 0;
|
||||||
|
|
||||||
|
|
||||||
|
void err_args() {
|
||||||
|
printf("[~] Usage: calcul [-m [1|2]] [-t #] [-i ##]\n");
|
||||||
|
printf("Aide :\n -i [ITÉRATIONS]\n -m [MÉTHODE]\n -t [THREAD] (max: 16)\n -v, verbose output\n");
|
||||||
|
exit(-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void * fn_thread_m1 (void * p_int) {
|
||||||
|
int nb_t = *(int *) p_int;
|
||||||
|
int lt = (D / nb_t) + 1;
|
||||||
|
int num = t_num;
|
||||||
|
++t_num;
|
||||||
|
|
||||||
|
for (int i = num * lt; i < (num+1)*lt && i < D; ++i){
|
||||||
|
for (int j = 0; j < D; ++j){
|
||||||
|
V_plus[i] += V[j] * A[i][j];
|
||||||
|
//compt_glob++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pthread_exit(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void * fn_thread_m2 (void * p_int) {
|
||||||
|
int nb_t = *(int *) p_int;
|
||||||
|
int lt = (D / nb_t) + 1;
|
||||||
|
int num = t_num;
|
||||||
|
++t_num;
|
||||||
|
|
||||||
|
for (int j = 0; j < D; ++j){
|
||||||
|
for (int i = num * lt; i < (num+1)*lt && i < D; ++i){
|
||||||
|
V_plus[i] += A[i][j] * V[j];
|
||||||
|
//compt_glob++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pthread_exit(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
int main (int argc, char **argv) {
|
||||||
|
// On parse les arguments
|
||||||
|
int c;
|
||||||
|
extern char *optarg;
|
||||||
|
extern int optind;
|
||||||
|
int method = -1;
|
||||||
|
int nb_t = -1;
|
||||||
|
int ite = -1;
|
||||||
|
int v = 0; //verbose
|
||||||
|
|
||||||
|
|
||||||
|
while ((c = getopt(argc, argv, "m:t:i:v")) != -1) {
|
||||||
|
switch (c) {
|
||||||
|
case 'm':
|
||||||
|
method = atoi(optarg);
|
||||||
|
if (method != 1 && method != 2) err_args();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 't':
|
||||||
|
nb_t = atoi(optarg);
|
||||||
|
if (nb_t > 16) err_args();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'i':
|
||||||
|
ite = atoi(optarg);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'v':
|
||||||
|
v = 1;
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
err_args();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (method < 0 || nb_t < 0 || ite < 0) err_args();
|
||||||
|
|
||||||
|
printf("Lancement du programme...\nMéthode %d, %d thread(s) et %d itération(s)\n", method, nb_t, ite);
|
||||||
|
|
||||||
|
//Fichier de sauvegarde
|
||||||
|
FILE* fichier = NULL;
|
||||||
|
fichier = fopen("calcul.txt", "w");
|
||||||
|
fprintf(fichier, "Méthode %d - %d thread(s) - %d itération(s)\n", method, nb_t, ite);
|
||||||
|
|
||||||
|
//On initialise les tableaux
|
||||||
|
//srand(time(NULL));
|
||||||
|
if (!v) goto no_verbose1;
|
||||||
|
srand(0);
|
||||||
|
for (int i = 0; i < D; ++i){
|
||||||
|
V[i] = (rand() % 20) - 10;
|
||||||
|
V_plus[i] = 0;
|
||||||
|
for (int j = 0; j < D; ++j)
|
||||||
|
A[i][j] = (rand() % 20) - 10;
|
||||||
|
}
|
||||||
|
|
||||||
|
printf("Tableaux initialisés : \nV(0) = [ ");
|
||||||
|
for (int i = 0; i < D; ++i)
|
||||||
|
printf("%d, ", V[i]);
|
||||||
|
printf("]\n");
|
||||||
|
|
||||||
|
printf("A = [\n");
|
||||||
|
for (int i = 0; i < D; ++i){
|
||||||
|
for (int j = 0; j < D; ++j)
|
||||||
|
printf("%d, ", A[i][j]);
|
||||||
|
printf("\n");
|
||||||
|
}
|
||||||
|
printf("]\n");
|
||||||
|
|
||||||
|
no_verbose1:
|
||||||
|
;
|
||||||
|
struct timeval begin, end;
|
||||||
|
gettimeofday(&begin, NULL);
|
||||||
|
|
||||||
|
pthread_t threads[nb_t];
|
||||||
|
for (int it = 0; it < ite; ++it){
|
||||||
|
// Lancement des threads en fonction de la méthode
|
||||||
|
for (int j = 0; j < nb_t; ++j) {
|
||||||
|
if (method == 1) pthread_create(&threads[j], NULL, fn_thread_m1, (void*) &nb_t);
|
||||||
|
else pthread_create(&threads[j], NULL, fn_thread_m2, (void*) &nb_t);
|
||||||
|
}
|
||||||
|
|
||||||
|
// On attend que tout les threads finissent leur partie
|
||||||
|
for (int i = 0; i < nb_t; ++i) pthread_join(threads[i], NULL);
|
||||||
|
for (int i = 0; i < D; ++i) {V[i] = V_plus[i]; V_plus[i] = 0;}
|
||||||
|
t_num = 0;
|
||||||
|
|
||||||
|
// On affiche le vecteur calculé
|
||||||
|
if (!v) goto no_verbose2;
|
||||||
|
printf("V(%d) = [ ", it + 1);
|
||||||
|
for (int i = 0; i < D; ++i)
|
||||||
|
printf("%d, ", V[i]);
|
||||||
|
printf("]\n");
|
||||||
|
no_verbose2:;
|
||||||
|
}
|
||||||
|
|
||||||
|
gettimeofday(&end, NULL);
|
||||||
|
printf("Time: %ld microseconds\n", ((end.tv_sec - begin.tv_sec)*1000000L + end.tv_usec) - begin.tv_usec);
|
||||||
|
printf("Nombre d'opération arithmétique : %d\n", compt_glob);
|
||||||
|
|
||||||
|
printf("Enregistrement...");
|
||||||
|
fprintf(fichier, "Temps d'exécution : %ld\n", ((end.tv_sec - begin.tv_sec)*1000000L + end.tv_usec) - begin.tv_usec);
|
||||||
|
fclose(fichier);
|
||||||
|
printf("fait.\n");
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
Loading…
Reference in a new issue