1 Université Ibn Khaldoun – Tiaret Module : Systèmes d’Exploitation II (TP) Niv
1 Université Ibn Khaldoun – Tiaret Module : Systèmes d’Exploitation II (TP) Niveau : 3 LMD Année : 2016-2017 Département d’Informatique Chargé du module : B.Boudaa Fiche TP N° 03 « Manipulation des Processus et Threads en langage C » Remarques: Les primitives de manipulation des processus sous Unix/Linux sont : L’appel fork() duplique un processus et le système crée alors une copie complète du processus, avec un PID différent. L’un des deux processus est fils de l’autre. fork() peut échouer par manque de mémoire ou si l’utilisateur a déjà créé trop de processus; dans ce cas, aucun fils n’est créé et fork()retourne -1 Lors de la création d’un nouveau thread dans un processus, il obtient sa propre pile (et de ce fait ses propres variables locales) mais partage avec son créateur les variables globales. Pour compiler un programme en langage C, on utilise soit gcc (logiciel libre dans la cadre du projet GNU/GPL) ou bien cc (compilateur c/c++) 1- En utilisant l’éditeur gedit, écrire les programmes suivants. 2- Compiler et exécuter ces programmes 3- Expliquer le déroulement de ces programmes Exercice 1 : gestion des processus par : fork(), pid() et ppid() /* Exemple utilisation primitive fork() sous Linux */ #include <stdio.h> #include <stdlib.h> #include <unistd.h> int main(void) { int pid; /* PID du processus fils */ int i; pid = fork(); switch (pid) { case -1: printf("Erreur: echec du fork()\n"); exit(1); break; ps [-e][-l] : Affiche la liste des processus - L’option -e : permet d’afficher les processus de tous les utilisateurs. - L’option -l : permet d’obtenir plus d’informations dont les plus importantes sont: (UID: identité du propriétaire du processus; – PID: numéro du processus; – PPID: PID du père du processus; – NI: priorité (nice); – S: état du processus(R si actif, S si bloqué, Z si terminé). signal() : gestion des signaux fork() : création d’un processus pause() : mise en sommeil sur l’arrivée d’un signal wait() : mise en sommeil sur la terminaison d’un fils sleep() : mise en sommeil sur une durée déterminée (argument) kill() : envoi de signal à un processus exit() : terminaison d’un processus (pour plus d’informations, voir le man de chaque primitive) cprocessus.c 2 case 0: /* PROCESSUS FILS */ printf("je suis le processus fils : PID=%d , mon pere est : PPID=%d\n", getpid(), getppid()); exit(0); /* fin du processus fils */ break; default: /* PROCESSUS PERE */ printf("Ici le pere: le fils a un pid=%d\n", pid ); wait(0); /* attente de la fin du fils */ printf("Fin du pere.\n"); } } Exercice 2 : gestion des threads à l’aide de l’API POSIX (pthread.h) Ce programme crée un autre thread qui va montrer qu’il partage des variables avec le thread original, et permettre au "petit nouveau" de renvoyer un résultat à l’original. N.B: - pour compiler ce programme il faut établir un lien avec la bibliothèque des threads : gcc –o cthread cthread.c –lpthread - pthread_create: crée un nouveau thread (comme le "fork" pour un processus) - pthread_join: fait attendre la fin d’un thread (comme "wait" pour les processus) - pthread_exit : termine un thread (comme "exit" pour les processus) #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <pthread.h> #include <string.h> void *fonction_de_thread(void *arg); char message[] = "Hello World"; int main() { int res; pthread_t un_thread; void *resultat_de_thread; res=pthread_create(&un_thread, NULL, fonction_de_thread, (void*)message); if (res != 0) { perror("Echec de la creation du thread "); exit(EXIT_FAILURE); } printf("En attente de terminaison du thread ...\n"); res=pthread_join (un_thread, &resultat_de_thread); if (res != 0) { perror("Echec de l’ajout de thread "); exit(EXIT_FAILURE);} printf("Retour du thread, il a renvoye %s\n",(char *)resultat_de_thread); printf("Voici a present le message %s\n", message); exit(EXIT_SUCCESS); } void *fonction_de_thread (void *arg) { printf("la fonction_de_thread est en cours d’execution. L’argument était : %s\n", (char *) arg); sleep (3); strcpy(message, "Salut !"); pthread_exit("Merci pour le temps processeur");} Adresse de l’identifiant du thread créé Fonction exécutée par le thread créé Paramètre passé à la fonction Identifiant du thread attendu adresse de l’objet renvoyé au thread appelant cthread.c 3 Université Ibn Khaldoun – Tiaret Module : Systèmes d’Exploitation II (TP) Niveau : 3 LMD Année : 2016-2017 Département d’Informatique Chargé du module : B.Boudaa Fiche TP N° 04 « Threads et Sémaphores avec API POSIX » Remarques : Commandes pour les process (processus : programme en exécution) ps [-e][-l] : Affiche la liste des processus - L’option -e : permet d’afficher les processus de tous les utilisateurs. - L’option -l : permet d’obtenir plus d’informations dont les plus importantes sont: (UID: identité du propriétaire du processus; – PID: numéro du processus; – PPID: PID du père du processus; – NI: priorité (nice); – S: état du processus(R si actif, S si bloqué, Z si terminé). 1) Pour compiler et effectuer l'édition de liens vous devez utiliser la ligne suivante : gcc –o votre_programme votre_programme.c –lpthread ou bien gcc votre_programme.c -lpthread -o votre_programme 2) Utilisation de man pour toute aide sur l’utilisation des fonctions ci-après. Partie 1: Les threads LINUX (processus de poids légers) Les threads de LINUX sont gérés à la fois par le système et par une librairie au niveau utilisateur. Voici quelques fonctions standards de la l’API POSIX (API : Application Programming Inteface et POSIX : Portable Operating System Interface, dont le X exprime l'héritage UNIX de l'API) pthread_create( thread, attribut, routine, argument ) Création d'un thread. Le nouveau flot d'exécution démarre en se branchant à la routine spécifiée. Cette routine reçoit l'argument prévu. pthread_exit( résultat ) Suicide d'un thread. pthread_join( thread, résultat ) Attendre la terminaison d'un autre thread. pthread_kill( thread, nu_du_signal ) Envoyer un signal (UNIX) à un thread. C'est un moyen dur pour tuer un thread. sched_yield() Abandonner la CPU pour la donner à un autre thread (ou un autre processus). Attention : il n'existe pas de préemption de la CPU à l'intérieur des threads d'un même processus. En clair, si un thread garde la CPU, les autres threads ne vont pas s'exécuter. Cette routine permet de programmer un partage équitable de la CPU entre threads coopératifs. 4 Exercice 1 : gestion des threads à l’aide de l’API POSIX (pthread.h) Un thread lit des caractères au clavier et les passe à un autre thread qui se charge de les afficher. Il faut noter que le thread principal (le père) se charge de la création de ses fils et de l'attente de leur mort. Cette disparition est programmée à l'arrivée du caractère "F". Partie 2: Utilisation des sémaphores pour synchroniser les threads La librairie de gestion des threads offre les fonctions ci-dessous pour créer et utiliser des sémaphores. Attention : ces sémaphores sont propres à un processus. Ils permettent de synchroniser plusieurs threads entre eux, mais ils ne peuvent synchroniser plusieurs processus. Pour réaliser cette synchronisation il faut se tourner vers les sémaphores système V basés sur les IPC (Inter Processus Communication). #include <stdio.h> #include <stdlib.h> #include <pthread.h> volatile char theChar = '\0'; volatile char afficher = 0; void* lire (void* name) { do { while (afficher == 1) ; /* attendre mon tour */ theChar = getchar(); afficher = 1; /* donner le tour */ } while (theChar != 'F'); return NULL; } void* affichage (void* name) { int cpt = 0; do { while (afficher == 0) cpt ++; /* attendre */ printf("cpt = %d, car = %c\n", cpt, theChar); afficher = 0; /* donner le tour */ } while (theChar != 'F'); return NULL; } int main (void) { pthread_t filsA, filsB; if (pthread_create(&filsA, NULL, affichage, "AA")) { perror("pthread_create"); exit(EXIT_FAILURE); } if (pthread_create(&filsB, NULL, lire, "BB")) { perror("pthread_create"); exit(EXIT_FAILURE); } if (pthread_join(filsA, NULL)) perror("pthread_join"); if (pthread_join(filsB, NULL)) perror("pthread_join"); printf("Fin du pere\n") ; return (EXIT_SUCCESS); } 5 int sem_init(sem_t *semaphore, int pshared, unsigned int valeur) Création d'un sémaphore et préparation d'une valeur initiale. int sem_wait(sem_t * semaphore); Opération P sur un sémaphore. int sem_trywait(sem_t * semaphore); Version non bloquante de l'opération P sur un sémaphore. int sem_post(sem_t * semaphore); Opération V sur un sémaphore. int sem_getvalue(sem_t * semaphore, int * sval); Récupérer le compteur d'un sémaphore. int sem_destroy(sem_t * semaphore); Destruction d'un sémaphore. Exercice 2 : utilisation des sémaphores à l’aide de l’API POSIX (pthread.h) Cet exercice illustre la mise en oeuvre d'une section critique (mutuelle exclusion) permettant d'éviter un mélange des affichages réalisés par les deux threads. #include <stdio.h> #include <stdlib.h> #include <pthread.h> #include <semaphore.h> #include <unistd.h> sem_t mutex; void* affichage (void* name) { int i, j; for(i = 0; i < 20; i++) { sem_wait(&mutex); /* prologue */ for(j=0; j<5; j++) printf("%s ",(char*)name); sched_yield(); /* pour etre sur d'avoir des problemes */ for(j=0; j<5; j++) printf("%s ",(char*)name); printf("\n "); sem_post(&mutex); /* epilogue */ } return NULL; } int main (void) { pthread_t filsA, filsB; sem_init(&mutex, 0, 1); if (pthread_create(&filsA, NULL, affichage, "AA")) { perror("pthread_create"); exit(EXIT_FAILURE); } if (pthread_create(&filsB, NULL, affichage, "BB")) { perror("pthread_create"); exit(EXIT_FAILURE); } if (pthread_join(filsA, NULL)) perror("pthread_join"); if (pthread_join(filsB, NULL)) perror("pthread_join"); printf("Fin du pere\n") ; return (EXIT_SUCCESS); } 6 Université Ibn Khaldoun – Tiaret Module : Systèmes d’Exploitation II (TP) Niveau : 3 LMD Année : 2016-2017 Département d’Informatique Chargé du uploads/Industriel/ systemesexploitationii-tps-n3-4-5-6.pdf
Documents similaires
-
13
-
0
-
0
Licence et utilisation
Gratuit pour un usage personnel Attribution requise- Détails
- Publié le Nov 17, 2021
- Catégorie Industry / Industr...
- Langue French
- Taille du fichier 0.5949MB