
































Study with the several resources on Docsity
Earn points by helping other students or get them with a premium plan
Prepare for your exams
Study with the several resources on Docsity
Earn points to download
Earn points by helping other students or get them with a premium plan
fork(),thread(),sémaphores,commandes
Typology: Study Guides, Projects, Research
Uploaded on 12/15/2018
1 / 40
This page cannot be seen from the preview
Don't miss anything!

































1.1.2 Liste complète des processus
L’option -f (full ) permet d’afficher d’autres informations (colonnes) sur un processus. En plus des champs affichés par l’option -e, on trouve UID (identifiant de l’utilisateur), PPID (identifiant du processus père), C (rapport du temps d’utilisation du CPU sur le temps d’exécution) et STIME (date de démarrage du processus). L’option -f peut être combinée avec d’autres options pour afficher des colonnes addi- tionnelles.
Exemple:
laloukil@laloukil:~$ ps -ef UID PID PPID C STIME TTY TIME CMD root 1 0 0 19:24? 00:00:01 /sbin/init root 2 0 0 19:24? 00:00:00 [kthreadd] root 3 2 0 19:24? 00:00:00 [ksoftirqd/0] root 5 2 0 19:24? 00:00:00 [kworker/0:0H] root 7 2 0 19:24? 00:00:01 [rcu_sched] root 8 2 0 19:24? 00:00:00 [rcuos/0] root 9 2 0 19:24? 00:00:00 [rcuos/1] root 10 2 0 19:24? 00:00:00 [rcuos/2] root 11 2 0 19:24? 00:00:00 [rcuos/3] .....
Remarque: Il est parfois utile de relier en pipe la commande ps avec la commande more, less ou grep pour prendre le temps de consulter les longues listes de processus (cas des commandes more et less) ou pour filtrer le résultat de la commande ps et n’afficher que les informations utiles (cas de la commande grep).
Exemples:
laloukil@laloukil:~$ ps -A | more
laloukil@laloukil:~$ ps -A | less
laloukil@laloukil:~$ ps -A | grep firefox 12494? 00:01:20 firefox
1.1.3 Liste des processus d’un utilisateur spécifique
Pour sélectionner les processus attachés à un utilisateur spécifique, on utilise l’option -u suivie du nom de l’utilisateur. Plusieurs utilisateurs peuvent être indiqués, il suffit de les séparer par une virgule.
La commande suivante permet d’afficher les processus de l’utilisateur root:
laloukil@laloukil:~$ ps -f -u root UID PID PPID C STIME TTY TIME CMD root 1 0 0 10:10? 00:00:01 /sbin/init root 2 0 0 10:10? 00:00:00 [kthreadd] root 3 2 0 10:10? 00:00:00 [ksoftirqd/0] root 4 2 0 10:10? 00:00:00 [kworker/0:0] .....
1.1.4 Liste des processus par nom ou par PID
L’option -C filtre les processus par commande ou nom de processus. La commande suivante affiche tous les processus getty:
laloukil@laloukil:~$ ps -f -C getty UID PID PPID C STIME TTY TIME CMD root 901 1 0 10:10 tty4 00:00:00 /sbin/getty -8 38400 tty root 905 1 0 10:10 tty5 00:00:00 /sbin/getty -8 38400 tty root 911 1 0 10:10 tty2 00:00:00 /sbin/getty -8 38400 tty root 912 1 0 10:10 tty3 00:00:00 /sbin/getty -8 38400 tty root 915 1 0 10:10 tty6 00:00:00 /sbin/getty -8 38400 tty root 1059 1 0 10:10 tty1 00:00:00 /sbin/getty -8 38400 tty
L’option -p filtre les processus par leur PID. La commande suivante affiche les processus de PID 3564 et 3582 :
laloukil@laloukil:~$ ps -f -p 3564, UID PID PPID C STIME TTY TIME CMD root 3564 2 0 11:14? 00:00:00 [kworker/1:0] root 3582 2 0 11:23? 00:00:00 [kworker/0:2]
1.1.5 Tri des processus par utilisation du CPU et de la mémoire
Un administrateur système a souvent besoin de connaître les processus gourmands en temps CPU et en mémoire. L’option --sort permet de trier la liste des processus sur un champ donné ou un paramètre particulier.
Plusieurs champs peuvent être spécifiés avec l’option --sort. Les champs doivent être dans ce cas séparés par une virgule. Les champs peuvent être préfixés par le signe "-"
Comme pour la commande ps, pstree peut être reliée en pipe avec les commandes more, less ou grep pour consulter ou chercher un processus dans l’arborescence.
La commande top offre une vue dynamique et en temps réel de l’activité du système. Elle affiche des informations de synthèse sur l’utilisation de la mémoire et du processeur, suivies de la liste des processus et threads actuellement gérés par le noyau Linux. Les informations sur le système, le type, l’ordre et la taille des informations sur les processus peuvent être configurés par l’utilisateur. La commande fournit une interface interactive pour la manipulation des processus. Elle permet de trier les processus par utilisation du CPU, utilisation de la mémoire, etc. (voir manuel de la commande pour plus de détails).
Un exemple d’informations affichées par top est donné ci-dessous:
La commande top organise les informations affichées en deux zones: zone de synthèse et zone des tâches.
La zone de synthèse donne des informations sur l’état général du système telles que le nombre total de processus, le nombre de processus en exécution, nombre de processus endormis, etc. Nous mettons l’accent sur la troisième, quatrième et cinquième ligne qui donnent des informations respectivement sur l’utilisation du CPU, de la mémoire physique et de la mémoire virtuelle.
La troisième ligne donne différents pourcentages d’utilisation du CPU. Nous expliquons ci-après la signification des différentes abréviations:
La quatrième ligne reflète la mémoire physique. Les champs affichés sont total, used (mémoire utilisée incluant le cache disque), free (libre) et buffers (mémoire utilisée pour les E/S).
La cinquième ligne reflète la mémoire virtuelle. Le champ cached est la taille de la mémoire utilisée par le cache disque.
La zone des tâches affiche une liste triée des processus en cours d’exécution sur votre système. Par défaut, la liste est triée par ordre décroissant d’utilisation du processeur; la liste peut cependant être triée sur d’autres champs tels que le taux d’occupation de la mémoire, par exemple. Différents champs peuvent être affichés dans la zone des tâches; les champs par défaut sont:
noyau Linux en cours d’exécution. Beaucoup d’utilitaires systèmes sont simplement des appels à des fichiers de /proc.
Dans ce qui suit, nous allons décrire quelques fichiers et répertoires sous /proc. Pour de plus amples détails, se référer aux pages du manuel de proc.
appelant est appelé processus père, le processus créé par le processus père est appelé processus fils. Au moment de l’appel de fork(), les espaces mémoires du père et du fils ont le même contenu. Par la suite, les écritures mémoires effectuées par l’un des processus n’affectent pas la mémoire de l’autre processus.
Le processus fils est une copie exacte du processus père sauf sur les points suivants (voir le manuel de fork() pour plus de détails):
Synopsis 1 #i n c l u d e 2 3 pid_t f o r k ( v o i d ) ;
En cas de succès, fork() retourne le PID du processus fils dans le processus père, et la valeur 0 dans le processus fils. La valeur retournée par fork() permet donc au programmeur de distinguer la partie de code exécutée par le processus père de celle exécutée par le processus fils. En cas d’échec, -1 est retourné dans le père et aucun processus fils n’est créé.
Exemple 3. Dans l’exemple suivant, le processus main crée un processus fils, affiche Hello, s’endort pendant 100 secondes et se termine. Le processus fils créé par fork() affiche également Hello, s’endort pendant 100 secondes et se termine. Vous allez constater que deux Hello seront affichés à l’écran. 1 #i n c l u d e 2 #i n c l u d e < s t d l i b. h> 3 #i n c l u d e <s y s / t y p e s. h> 4 #i n c l u d e 5 6 i n t main ( ) { 7 f o r k ( ) ; 8 p r i n t f ( " H e l l o du p r o c e s s u s %d dont l e p e r e e s t %d\n" , g e t p i d ( ) , g e t p p i d ( ) ) ; 9 s l e e p ( 1 0 0 ) ; 10 r e t u r n 0 ;
11 }
Exemple 3. Dans cet exemple, le processus main crée un processus fils, affiche son PID, s’endort pendant 600 secondes, affiche un message de fin d’exécution et se termine. En cas de succès de l’appel fork(), le processus fils affiche son PID, s’endort pendant 10 secondes, affiche un message de fin d’exécution et se termine. En cas d’échec de l’appel de fork(), un message d’erreur est affiché et le programme se termine. 1 #i n c l u d e 2 #i n c l u d e <s y s / t y p e s. h> 3 #i n c l u d e 4 #i n c l u d e < s t d l i b. h> 5 6 i n t main ( v o i d ) { 7 pid_t p id ; 8 p i d = f o r k ( ) ; 9 s w i t c h ( pi d ) { 10 c a s e − 1 : // e c h e c dans f o r k ( ) 11 f p r i n t f ( s t d e r r , " e c h e c du f o r k. \ n" ) ; 12 e x i t ( 1 ) ; 13 break ; 14 c a s e 0 : // p id == 0 : p a r t i e du code e x e c u t e e par l e f i l s 15 f p r i n t f ( stdout , " F i l s : j e demarre. Mon PID e s t %u. \ n" , g e t p i d ( ) ) ; 16 s l e e p ( 1 0 ) ; 17 f p r i n t f ( stdout , " F i l s : j e t e r m i n e. \ n" ) ; 18 e x i t ( 0 ) ; 19 break ; 20 d e f a u l t : // p i d > 0 : p a r t i e du code e x e c u t e e par l e p r o c e s s u s p e r e 21 f p r i n t f ( stdout , " Pere : j e demarre. Mon PID e s t %u. \ n" , g e t p i d ( ) ) ; 22 s l e e p ( 6 0 0 ) ; // S i m u l e r une e x e c u t i o n de 600 s e c. ∗/ 23 f p r i n t f ( stdout , " Pere : j e t e r m i n e. \ n" ) ; 24 e x i t ( 0 ) ; 25 break ; 26 } 27 r e t u r n ( 0 ) ; 28 }
Les fonctions wait() et waitpid() permettent de suspendre le processus appelant jusqu’à ce que l’un de ses processus fils se termine.
Synopsis: 1 #i n c l u d e <s y s / t y p e s. h> 2 #i n c l u d e <s y s / wait. h> 3 4 pid_t w ait ( i n t ∗ s t a t u s ) ;
7 i n t main ( v o i d ) { 8 pid_t p id ; 9 f p r i n t f ( stdout , " Pere : j e demarre. Mon PID e s t %u. \ n" , g e t p i d ( ) ) ; 10 p i d = f o r k ( ) ; 11 s w i t c h ( pi d ) { 12 c a s e − 1 : // e c h e c de f o r k ( ) 13 f p r i n t f ( s t d e r r , " e c h e c du f o r k. \ n" ) ; 14 e x i t ( 1 ) ; 15 break ; 16 c a s e 0 : // p id == 0 : p a r t i e du code e x e c u t e e par l e f i l s 17 f p r i n t f ( stdout , " F i l s : j e demarre. Mon PID e s t %u. \ n" , g e t p i d ( ) ) ; 18 s l e e p ( rand ( ) %20) ; 19 f p r i n t f ( stdout , " F i l s : j e t e r m i n e e t j e s o r s. \ n" ) ; 20 e x i t ( 0 ) ; 21 break ; 22 d e f a u l t : // p i d > 0 : p a r t i e du code e x e c u t e e par l e p e r e 23 f p r i n t f ( stdout , " Pere : J ’ a t t e n d s l a t e r m i n a i s o n de mon f i l s %u\n" , p i d ) ; 24 wai t (NULL) ; 25 f p r i n t f ( stdout , " Pere : Mon f i l s %u s ’ e s t t e r m i n e. Je s o r s. \ n" , p i d ) ; 26 e x i t ( 0 ) ; 27 break ; 28 } 29 r e t u r n ( 0 ) ; 30 }
Lorsqu’un processus crée un processus fils avec fork(), le processus fils hérite et exécute le même code que le processus père. Souvent, on a besoin de faire exécuter par le processus fils un programme différent du programme exécuté par le père. Ceci peut être réalisé avec les appels systèmes exec(). Lorsqu’un processus exécute exec(), il remplace le code courant par le code du programme dont le chemin est indiqué en premier paramètre de la fonction exec(). Dans ce recueil de travaux pratiques, nous nous focalisons sur 2 fonctions: execl() et execv().
Synopsis 1 #i n c l u d e 2 3 i n t e x e c l ( c o n s t char ∗ path , c o n s t char ∗ arg0 ,... , char ∗ argn ) ; 4 i n t execv ( c o n s t char ∗ path , char ∗ c o n s t argv [ ] ) ;
Ces fonctions renvoient –1 en cas d’échec. Les fonctions execl() et execv() sont iden- tiques et ne diffèrent que de la façon dont les arguments sont fournis à la fonction.
Pour execl(), les arguments sont fournis sous forme d’une liste terminée par le pointeur NULL:
Pour la fonction execv(), les arguments sont fournis dans un vecteur de chaînes de caractères dont le dernier argument est la valeur NULL :
En cas de succès de l’appel de execl()(ou execv()), le processus charge puis exécute le code du programme dont le chemin est indiqué comme premier argument de l’appel exec() et les instructions qui suivent l’appel de exec() ne sont pas exécutées. En cas d’échec de recouvrement de code (renvoie de la valeur -1), l’exécution se poursuit à partir de l’instruction qui suit l’appel de exec().
Il existe de nombreuses autres fonctions de la famille de fonctions exec(): execle(), execve(), execlp(), execvp(). Pour plus de détails, consulter le manuel de ces fonc- tions.
Exemple 3. Dans cet exemple, le processus courant est remplacée par le processus ls. En cas de succès de l’appel de execl(), c’est la commande ls -l qui sera exécutée. En cas d’échec, c’est le message "Erreur lors de l’exécution de ls." qui sera affiché à l’écran.
1 #i n c l u d e 2 #i n c l u d e 3 4 i n t main ( ) { 5 e x e c l ( "/ b i n / l s " , " l s " , "−l " , NULL) ; 6 p r i n t f ( " E r r e u r l o r s de l ’ e x c u t i o n de l s. \n" ) ; 7 r e t u r n 0 ; 8 }
Exemple 3. Le même exemple que précédemment avec l’utilisation de la fonction execv().
1 #i n c l u d e 2 #i n c l u d e 3 4 #d e f i n e NMAX 5 5
11 p r i n t f ( "Avant f o r k : Je s u i s l e p r o c e s s u s main , mon p i d e s t = %d\n" , p i d ) ; 12 s l e e p ( 2 0 ) ; 13 p r i n t f ( " Appel de f o r k par l e p r o c e s s u s main de PID = %d... \n" , g e t p i d ( ) ) ; 14 p i d = f o r k ( ) ; // Clonage du p r o c e s s u s 15 s w i t c h ( p id ) { 16 c a s e −1: // p id = −1: e r r e u r du f o r k ( ) 17 f p r i n t f ( s t d e r r , " e r r e u r du f o r k. \ n" ) ; 18 e x i t ( 1 ) ; 19 break ; 20 21 c a s e 0 : // p i d = 0 : on e s t dans l e f i l s 22 f p r i n t f ( stdout , " Fork r e u s s i... Je s u i s l e p r o c e s s u s f i l s c r e e par f o r k : mon PID e s t = %d , l e PID de mon p e r e e s t = %d\n" , g e t p i d ( ) , g e t p p i d ( ) ) ; 23 s l e e p ( 3 0 ) ; 24 f p r i n t f ( stdout , " Fin du f i l s ( PID=%d ) , i=%d... \n" , g e t p i d ( ) , i ) ; 25 e x i t ( 0 ) ; 26 break ; 27 28 d e f a u l t : // p id > 0 : on e s t dans l e p e r e 29 // M o d i f i c a t i o n de l a v a r i a b l e i par l e p e r e 30 i = 2 ; 31 f p r i n t f ( stdout , " Je s u i s l e p r o c e s s u s pere , j e v i e n s de m o d i f i e r l a v a r i a b l e i , i= %d\n" , i ) ; 32 s l e e p ( 1 0 ) ; 33 p r i n t f ( " Fin du p e r e ( PID=%d ) , i = %d... \n" , g e t p i d ( ) , i ) ; 34 e x i t ( 0 ) ; 35 break ; 36 } 37 }
(a) Compilez puis exécutez le programme. (b) Quelle est la valeur de la variable i affichée dans le fils? Quelle est la valeur de la variable i affichée dans le père? Sont-elles égales? Pourquoi?
7 } 8 }
(a) Exécutez le programme, ouvrez un second terminal et exécuter la commande ps -a. Que remarquez-vous? (b) Mettez en commentaire l’instruction sleep(30) et exécuter la commande ps -a. Que remarquez-vous?
(a) hello1.c 1 #i n c l u d e 2 3 i n t main ( ) { 4 p r i n t f ( " H e l l o! \ n" ) ; 5 r e t u r n 0 ; 6 }
(b) hello2.c 1 #i n c l u d e 2 #i n c l u d e 3 4 i n t main ( ) { 5 p r i n t f ( " H e l l o! \ n" ) ; 6 f o r k ( ) ; 7 r e t u r n 0 ; 8 }
(c) hello3.c 1 #i n c l u d e 2 #i n c l u d e 3 4 i n t main ( ) { 5 f o r k ( ) ; 6 p r i n t f ( " H e l l o! \ n" ) ; 7 r e t u r n 0 ; 8 }
(d) hello4.c