Vous êtes sur la page 1sur 10

Ecole NATIONALE des Sciences de l’InforMATIque A. U.

: 2019/2020
Systèmes d’ExploitATIon& PrOGRAMMATIon Concurrente II2

TD (correction)

Gestion des Processus/Threads sous Linux

I. Gestion des Processus


TP. 1
Afin de vous familiariser avec les différentes commandes du shell Unix n’hésitez pas à
utiliser le man.

1) Quel est le processus de pid 1 ? justifier


2) Quelle est la différence entre les commandes ps et top?

3) Que fait la commande pstree?

4) Comment utiliser la commande ps pour obtenir la liste des processus en première


colonne et leur état en 2ème colonne ? Quels sont les états possibles ?

5) Ecrire un programme C qui engendre 6 processus liés au ancêtre de la manière


suivante:

En affichez l’identité de chaque processus ainsi que celle du parent.

Correction

1) Utiliser les options l a x de ps pour pouvoir voir le processus init.


2) La commande "ps" retourne un "cliché" de vos processus en cours sur la
machine, ainsi que les ressources consommées par ceux-ci.
"top" permet de donner les mêmes informations que ps mais en temps réel.
3) pstree : Afficher un arbre des processus .
4) Utiliser les options –o (et –e pour sélectionner tout les processus) de ps pour
pouvoir voir chaque processus dans un format défini (par l’utilisateur).
1
États d’un processus :

5) # include <unistd .h>


int main()
{
if(fork())
fork()&& (fork() ||(fork()&& fork()));
else
fork();
sleep(2);
return 0;
}

Exercice 0 (QCM --Exam. Rat. 04/2017)


Supposons l’entier n initialisé à 0, le nombre de processus créés par l’instruction, ci-dessous, est:
while (pid=fork()) if (n >= 5) break ; else n=n+1;

a) 4
b) 5
c) 6
d) >10

2
e) aucune des réponses ci-dessus.

Sélectionnez une ou plusieurs réponses

Exercice 1 (Recueil examens)


1) (Exam 3/01/2017)
Combien de processus sont créés par le code C suivant (où n est un entier initialisé à 0)
while (pid=fork()) if (n >= 5) break; else n++;
En dessinez le graphe des processus.
2) (DS 14/11/2013)
Soit le programme suivant :

#include <unistd.h> while (fork() !=0 && i<2)


#include <stdio.h> i=i+1;
printf(" Process %d termine avec i=%d \n", getpid(), i);
int main ( ) { return 0;
int i=0 ; }

Supposez que les appels à la fonction fork ne retournent pas d’erreur.

1) Donnez l’arborescence des processus engendrés par ce programme.


2) Peut-on risquer d’engendrer un/des processus orphelin(s) et/ou zombie(s) ? si
oui justifiez vos réponses et dire comment peut-on le vérifier ?
3) Modifiez le code de la fonction main de manière à
a) éviter la présence éventuelle d’orphelins et zombies, et
b) créer la nouvelle arborescence suivante, où PP est le processus principal :

3
Correction

1) 6 processus fils sont créés par le père

2) 1)

2) P1 (ou P2) peut terminer son exécution avant que PP ne termine, et devenir en état
zombie. PP peut terminer son exécution avant que P3 ne termine, donc P3 devient
orphelin. Utiliser les options l a de ps pour la vérification.

3)
#include <unistd.h> while (fork() >=0 && <2){
#include <stdio.h> i=i+1;
wait();
int main ( ) { }
int i=0 ; printf(" Process %d termine avec i=%d \n", getpid(), i);
return 0;
}

Exercice 2 (DS 16/11/2012)


Combien de processus engendre l’exécution du programme C suivant et en donner
l’arborescence.
# include <unistd .h>
int main ( void )
{
fork () && ( fork () || fork () );
4
sleep (2);
return 0; }

Correction

Il faut noter que :


-Dans une instruction (a || b), b n’est évaluée que si l’évaluation de a donne faux (0 en langage
C).
- Dans une instruction (a && b), b n’est évaluée que si l’évaluation de a donne vrai (1 en
langage C).
Exercice 3 (DS 16/11/2018)
On considère le code C suivant :

#include <unistd.h>
#include <stdio.h>
#include <sys/types.h>
int main()
{
int i;
for(i=0;i<4;i++)
if(fork())break;
printf("Mon nom est <%c>",'A'+i);
return(EXIT_SUCCESS);
}

1) Donnez l’arborescence des processus engendrés par ce programme.


2) Quel affichage possible peut engendrer l’exécution de ce programme ?
3) Modifiez ce programme de façon à ce que les processus fassent leur affichage par ordre
alphabétique inversé du nom.

Exercice 4.
1) Lancer le programme ci-dessous avec les arguments 10 20. Tapez ps -la dans un autre
terminal avant la fin du père, avant la fin du fils. Quels sont les ppid du père et du fils ?
5
Donnez une explication.
2) Lancer le programme ci-dessous avec les arguments 10 0. Tapez ps -la dans un autre
terminal avant la fin du père. Que constatez-vous?

/**************************************************************/

#include <sys/types.h>
#include <unistd.h>
#include <stdio.h>
int main(int argc, char * argv[]) {
pid_t pid;
int attente_fils,attente_pere;
if(argc != 3)
perror("usage: ex1 n m\n");
attente_pere = atoi(argv[1]);
attente_fils = atoi(argv[2]);
switch(pid=fork()) {
case -1:
perror("fork error");
break;
case 0:
sleep(attente_fils);
printf("fils attente finie\n");
break;
default:
sleep(attente_pere);
printf("pere attente finie\n");
break;
}
return 0 ;
}

Correction

1) Le père meurt avant son fils, le fils devient orphelin.


2) Le fils meurt avant son père, le père est en sommeil, il ne lit pas le code de retour de son fils. Le fils
devient zombie.
Exercice 5.

Écrire un programme modulaire qui va créer un deuxième processus. Le père va afficher les
majuscules à l'écran et le fils les minuscules. Ici, le travail effectué par les 2 processus est trop
court et il n'y a pas entrelacement des exécutions. Pensez à mettre un "\n" à la fin de chaque
écriture afin de vider le buffer !

Correction
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
6
#include <wait.h>

void * minuscules ();


void * majuscules();

int main()
{
pid_t pid;

if (pid = fork()<0)
{
fprintf(stderr, "erreur fork");
exit(1) ;
}
if(pid > 0) /* père */
majuscules();
else /* fils */
minuscules();
wait(NULL);
return 0;
}
void * minuscules ()
{
char c;
for( c='a'; c<='z'; c++)
printf("%c \n", c);
exit(1);
}
void * majuscules()
{
char c ;
for( c='A'; c<='Z'; c++)
printf("%c \n", c);
exit(2);
}
Exercice 6.

Écrire un programme modulaire qui va créer un deuxième processus. Le père et le fils comptent
de 0 à 100000 et l'affiche à l'écran. Le père place un P devant son comptage et le fils un F.
Analysez le travail de l'ordonnanceur.

7
II. TP.Threads

La création et le lancement du thread se fait par :


pthread_tth1 ;
int ret ;

pthread_create (&th1, NULL, runDuThread, "1");


if (th1 == NULL) {
fprintf (stderr, "pthread_create error 1\n") ; exit(0) ;
}
Le thread exécutera alors la fonction runDuThreaddont le prototype est :
void* runDuthread (void *param) ;

Cette fonction est à écrire par le programmeur pour décrire le comportement du thread. Le
paramètre paramest un pointeurdont la valeur est celle passée en argument (le 4ème) de la
fonction pthread_create. Il permet de passer des données authread.

Si la fonction main se termine, le programme et tous les threads lancés se terminent aussi. Il faut
donc s'assurer avant determiner le programme que tous les threads ont fini leur travail. L'attente
de la terminaison d'un thread se fait comme ceci :
(void) pthread_join (th1, (void *)&ret) ;
Le paramètre retcontiendra la valeur retournée par la fonction pthread_exit (int val)à
exécuter avant de terminer un thread.
1. Écrire un programme qui lance 2 threads. L'un écrira les 26 minuscules à l'écran et l'autre
les 26 majuscules.
2. Écrire un programme qui initialise une variable globale à 0 et crée 2 threads. Chacun des
threads va incrémenter la variable N fois. Afficher la valeur de la variable à la fin de
l'exécution de chacun des threads.

Correction
1)
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

8
void * minuscules ();
void * majuscules();

int main()
{
int ret1, ret2;
pthread_t t1, t2;

if(( ret1 = pthread_create(&t1, NULL, minuscules, NULL))!=0)


{
fprintf(stderr, "erreur pthread_create");
exit(1) ;
}
if((ret2 = pthread_create (&t2, NULL, majuscules, NULL))!=0)
{
fprintf( stderr , "erreur pthread_create") ;
exit(1);
}
pthread_join( t1, NULL);
pthread_join( t2, NULL);
return 0;
}
void *minuscules ()
{
Char c;
for( c=’a’; c<=’z’; c++)
printf ("%c ", c);
pthread_exit(NULL) ;
}
void * majuscules()
{
char c ;
for( c=’A’; c<=’Z’; c++)
printf ("%c ", c);
pthread_exit(NULL) ;
}

2)
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

#define NB_THREADS 2
int var_globale ;

void* incrementation ( void* arg ) ;

int main()
{
pthread_t th[NB_THREADS] ;
9
int i, j;
int var_globale =0;
fprintf(stdout, "Donnez le nombre d’incrémentation de var_globale:");
scanf("%d", &i);
for(j = 0; j< NB_THREADS; j++){
if( pthread_create(&th[j] , NULL, incrementation, ( void*)&i ) != 0)
{
fprintf( stderr, " Erreur pthread_create\n ");
exit(EXIT_FAILURE) ;
}
}
for( j = 0; j< NB_THREADS;j++) {
pthread_join(th[j], NULL);
}
}
Void* incrementation(void* arg )
{
int borne_sup = *((int*)arg);
int i =0;
for(i =0; i<borne_sup; i++)
{
var_globale++;
}
printf("var_globale = %d\n", var_globale );
pthread_exit(NULL) ;
}

1
0