Explorer les Livres électroniques
Catégories
Explorer les Livres audio
Catégories
Explorer les Magazines
Catégories
Explorer les Documents
Catégories
Philippe M ARQUET
et les équipes pédagogiques successives∗
Ce document est le support de travaux dirigés et de travaux pratiques relatifs aux notions de
processus, exécutions concurrentes et signaux. On étudie la manipulation de ces notions par les
primitives POSIX et les fonctions de la librairie standard.
1 Clonage de processus
Exercice 1 (Compréhension du clonage simple)
Observez le programme suivant.
int main() {
pid_t pid;
pid = fork();
if (pid == 0) {
/* qui suis-je, le pere ou le fils ? */
printf("je suis le ...\n");
} else {
/* qui suis-je, le pere ou le fils ? */
printf("je suis le ...\n");
}
exit(EXIT_SUCCESS);
}
Question 1.2 Pouvez-vous déterminer l’ordre d’apparition des messages ? Si oui donnez-le, si-
non pourquoi ? Pouvez-vous alors déterminer un ordre partiel d’apparition des messages ?
Question 1.3 On ajoute dans le else, avant le printf l’instruction wait(NULL). Cela change-
t-il quelque chose ?
∗ Énoncé placé sous licence Creative Commons by-nc-sa (https://creativecommons.org/licenses/
by-nc-sa/3.0/deed.fr).
1
Question 1.4 Pour garantir un fonctionnement plus sûr de ce code, que manque-t-il ?
Question 2.2 Combien de processus sont lancés en tout (il pourra être utile de représenter sous
forme arborescente les processus) ?
Question 2.3 Quels appels systèmes peut-on utiliser pour changer l’affichage et permettre un
meilleur suivi des processus (savoir qui est fils de qui) ?
Question 3.2 Assurez que les processus fils affichent les entiers dans l’ordre croissant.
2
static void fc() { f(3, "fc"); }
int main() {
trif(fa, fb, fc);
fprintf(stderr, "terminaison de main()\n");
exit(EXIT_SUCCESS);
}
Exercice 5 (Multi-fourche)
La fonction multif() généralise la fonction trif() précédente.
typedef int (*func_t) (char *);
int multif (func_t f[], char *args[], int n);
Le type func_t est défini comme « pointeur sur une fonction à un paramètre chaîne de caractères
et retournant un entier ».
Les arguments de multif() sont un tableau de telles fonctions, un tableau des arguments
à passer à ces fonctions, et la taille n de ces tableaux. Chacune des fonctions est exécutée par
un processus différent. La fonction f[i]() sera appelée avec args[i] comme argument. Ce
processus se termine en retournant comme statut la valeur de la fonction.
La fonction multif() se termine elle-même en retournant la conjonction des valeurs retour-
nées par les processus fils : elle ne retourne EXIT_SUCCESS que si chacun des processus fils a
retourné EXIT_SUCCESS.
Pour tester en pratique cette multif(), on définira une fonction testfunc telle que :
— si son argument est la chaîne "true", elle retourne EXIT_SUCCESS,
— si son argument est la chaîne "false", elle retourne EXIT_FAILURE.
On définira aussi d’autres comportements sur d’autres valeurs de l’argument (fonction qui prend
du temps pour se terminer, par exemple en utilisant sleep, pour vérifier que les fonctions ne sont
pas exécutées les unes après les autres mais de façon concurrente, etc.).
Enfin la commande multif prendra en argument les valeurs des arguments pour testfunc
et se terminera avec la valeur de retour de multif() (./multif true false devra donc
déclencher multif() avec n = 2, le tableau f contiendra 2 fois testfunc, le tableau args
contiendra les chaînes "true" et "false" et se terminera en retournant EXIT_FAILURE).
Question 6.2 Comment faire en sorte que le père récupère le PID de son petit-fils ?
3
Commandes de gestion des processus
La commande ps affiche des informations sur les processus actifs. Sans options, elle affiche les pro-
cessus du même terminal que le processus ps. La sortie contient uniquement le pid du processus, le nom
du terminal, le temps cumulé d’exécution et le nom de la commande.
Les options les plus courantes sont :
-a liste tous les processus sauf ceux non associés à un terminal ;
-f donne plus d’information pour chaque processus ;
-u uidlist liste les processus des utilisateurs donnés dans uidlist.
Les commandes top et htop affichent les mêmes informations que ps en rafraîchissant périodiquement
l’affichage.
Question 6.3 Que penser, en terme de coût de copie mémoire, de cette technique du double
fork ?
2 Gestion de processus
4
Arguments de la ligne de commande
Le programme suivant argv.c affiche les arguments qui lui sont passés sur la ligne de commande
int main(int argc, char *argv[]) {
int i;
fprintf(stderr, " argc = %d\n", argc);
for (i = 0; i < argc; i++)
fprintf(stderr, "argv[%d] = %s\n", i, argv[i]);
exit(EXIT_SUCCESS);
}
Ces quelques exemples d’exécution explicitent la manière dont les arguments de la ligne de commande
sont gérés :
$ ./argv emacs xclock
argc = 3
argv[0] = ./argv
argv[1] = emacs
argv[2] = xclock
$ ./argv "vim test.c" "xclock -update 1" xterm
argc = 4
argv[0] = ./argv
argv[1] = vim test.c
argv[2] = xclock -update 1
argv[3] = xterm
Question 8.2 (Exécutez) Utilisez la commande kill pour terminer les processus fils.
Que se passe-t-il si vous tuez le processus père ?
Question 8.3 (Observez) Modifiez le programme de telle façon que le processus père attende,
par exemple sur une saisie clavier, avant de commencer à attendre la terminaison de ses processus
fils à l’aide de wait().
— Tuez un de ses processus fils et examinez l’état des processus à l’aide de la commande ps
-a. Expliquez le résultat.
— Faites continuer le processus père (saisie clavier) afin qu’il attende la terminaison de son
fils et examinez l’état des processus à l’aide de la commande ps -a.
3 Mutation de processus
Exercice 9 (condition)
Il s’agit d’implanter une commande on qui exécute une seconde commande cmd si et seulement
si l’exécution d’une première commande pred se termine sur un succès :
on pred do cmd
On utilise cette commande comme sur l’exemple suivant :
on test -r spool/file do lpr spool/file
qui ne fait appel à la commande d’impression lpr que si le fichier existe (commande test).
Exercice 10 (Redirection)
Il s’agit d’implanter une commande
to file cmd...
qui exécute les commandes cmd... les unes après les autres en redirigeant leur sortie standard
vers le fichier file qui est éventuellement tronqué au début de l’exécution de to.
5
Exercice 11 (Exécutions de commandes)
On désire implanter un programme do qui exécute indépendamment et simultanément une série
de commandes Shell données sur la ligne de commande. L’exécution du programme se termine
quand l’ensemble des commandes a terminé. Le programme retourne alors un statut formé de
la conjonction (et, option -a (and)) ou de la disjonction (ou, option -o) des statuts retournés par
les commandes selon la valeur de l’option. Par défaut (si l’utilisateur n’a précisé ni -a ni -o), on
utilisera la conjonction. La syntaxe est la suivante :
do [-a|-o] command...
On utilise cette commande do suivant l’exemple suivant :
do -a emacs firefox xterm
Question 11.4 Implantez cette extension de la commande do. Reportez-vous à l’encart page pré-
cédente explicitant la manière dont les arguments de la ligne de commande sont traités. Vous
pourrez utiliser la bibliothèque makeargv fournie pour générer un tableau argv à partir d’une
chaîne de caractères.
6
Validation de votre do
Vous mettrez au point un script permettant de valider votre do. Deux commandes seront particulièrement
utiles pour la mise au point : true (qui fait juste un exit(EXIT_SUCCESS)) et false (qui fait juste un
exit(EXIT_FAILURE)).
Vous testerez notamment :
— ce qui se passe quand vous exécutez une seule commande ;
— ce qui se passe quand vous êtes en mode -a et qu’au moins l’une des commandes échoue ;
— ce qui se passe quand vous êtes en mode -a et que toutes les commandes réussissent ;
— les cas similaires quand vous êtes en mode -o ;
— ce qui se passe quand vous êtes en mode -a -c et que l’une des commandes échoue plus vite
que la terminaison des autres ;
— les cas similaires quand elles n’échouent pas ou que le mode est -o -c ;
— les cas similaires en ajoutant -k au mode.
Pour en faire un test automatique, vous pourrez taper :
./do -o true true || echo "Erreur: or true true a renvoyé false"
./do -o false false && echo "Erreur: or false false a renvoyé true"
qui n’affiche des messages qu’en cas d’échec d’un des tests, par un mécanisme similaire à celui de l’exer-
cice 9 : dans les lignes de commandes cmd1 || cmd2, cmd2 n’est exécutée que si cmd1 a échoué ; dans
cmd1 && cmd2, cmd2 n’est exécutée que si cmd1 a réussi.
Comme commandes qui durent plus longtemps que true et false, vous pourrez utiliser xterm (que
vous pourrez fermer normalement). Vous pourrez aussi faire un petit programme presque aussi simple
que false mais attendant quelques secondes avant de se terminer.