CSC 3102 – Introduction aux systèmes d’exploitation

Portail informatique

TP5 – Processus

Pour faire les exercices, vous avez besoin de connaître le langage bash. Vous pouvez vous référer à l'annexe shell. Vous pouvez aussi trouver une liste d'astuces ici. Tous les exercices sont obligatoires, sauf les exercices notés « défi » ou « optionnel » qui sont optionnels. En particulier, les exercices notés « hors présentiel » sont supposés fait d'une séance sur la suivante.

  • Savoir observer les processus s'exécutant sur une machine
  • Manipuler un processus en cours d'exécution
  • Savoir tuer un (ensemble de) processus
  • Notions de concurrence

Observer un processus (∼15mn)

Retrouvez, à l'aide de la commande ps, le PID du processus bash.
$ ps -C bash PID TTY TIME CMD 219253 pts/0 00:00:00 bash

Sur MacOS, l'option -C n'existe pas, et il faut rechercher le processus à la main avec ps ax. Plutôt que de chercher à la main, vous pouvez bien sûr vous simplifier la vie en utilisant un pipe et la commande grep.

Autre alternative sur Linux : pgrep -l bash, équivalent à ps | grep bash mais omet le processus ps lui-même, et est donc plus correct.

Ajoutez l'option -l à la commande précédente et trouvez le nom du processus parent du processus bash.
$ ps -C bash -l F S UID PID PPID C PRI NI ADDR SZ WCHAN TTY TIME CMD 0 S 20083 219253 219250 0 80 0 - 5425 do_wai pts/0 00:00:00 bash $ ps 219250 PID TTY STAT TIME COMMAND 219250 ? S 0:00 sshd: mbacou@pts/0
Explication : le processus bash a pour PPID (Parent Process ID) 219250. Le processus dont le PID est 219250 est le processus sshd: mbacou@pts/0 (un nom étrange parce qu'il est lancé pour une session SSH).

Utilisez maintenant la commande pstree afin de trouver le PID du processus bash ainsi que le nom de son processus père.
$ pstree -p systemd(1)─┬ [...] ├─rtkit-daemon(1174)─┬─{rtkit-daemon}(1180) │ └─{rtkit-daemon}(1181) ├─sshd(955)───sshd(218983)───sshd(219250)───bash(219253)───pstree(220447) ├─sssd(799)─┬─sssd_autofs(4981) │ ├─sssd_be(857) │ ├─sssd_nss(941) │ └─sssd_pam(942) [...]

Le répertoire /proc/<un PID> contient des fichiers décrivant l'état du processus de PID <un PID>. Trouvez le fichier contenant la ligne de commande ayant servi à lancer le processus bash.
$ cat /proc/219253/cmdline -bash
Cette ligne de commande un peu spéciale s'explique parce que c'est SSH qui a lancé Bash.

Consultez la documentation de la commande yes. À quoi sert-elle ?
$ man yes yes - Afficher indéfiniment une chaîne de caractères jusqu'à ce que le processus soit tué.

Ouvrez un terminal et lancez la commande suivante :
$ yes "Unix, c'est super"
Pendant l'exécution de la commande yes, lancez la commande top dans un autre terminal. Quels sont les processus qui consomment le plus de CPU ?
$ top top - 11:37:10 up 1 day, 22:18, 5 users, load average: 0,99, 0,66, 0,58 Tasks: 196 total, 3 running, 193 sleeping, 0 stopped, 0 zombie %Cpu(s): 35,2 us, 21,0 sy, 0,0 ni, 43,8 id, 0,0 wa, 0,0 hi, 0,0 si, 0,0 st KiB Mem : 8084284 total, 196328 free, 6017816 used, 1870140 buff/cache KiB Swap: 10157052 total, 10132608 free, 24444 used. 1713808 avail Mem PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND 20963 trahay 20 0 555536 66864 44800 R 97,0 0,8 0:58.80 konsole 29136 trahay 20 0 6280 680 600 R 38,9 0,0 0:05.08 yes 29172 trahay 20 0 52432 4232 3444 R 0,7 0,1 0:00.08 top 20090 trahay 20 0 489252 29608 25480 S 0,3 0,4 0:00.91 kaccess 20234 trahay 20 0 312872 32668 26880 S 0,3 0,4 0:00.71 kded4 27266 trahay 20 0 591768 17852 14316 S 0,3 0,2 0:11.62 VBoxSVC 1 root 20 0 186956 3708 2520 S 0,0 0,0 0:02.12 systemd [...]
On remarque que le processus yes consomme beaucoup de CPU (ici, 38.9%) puisqu'il passe son temps à demander l'affichage du texte. Le processus konsole (ou gnome-terminal) consomme aussi beaucoup de CPU car il est chargé d'afficher à l'écran le texte tel que demandé par le processus yes.

Suspendre un processus (∼15mn)

Lancement en avant-plan

  1. Tapez la commande emacs pour lancer, en avant-plan, le processus emacs
    $ emacs
  2. Pour quelle raison l'invite de commande (prompt) n'est plus présente dans le terminal ? Tapez la commande ls dans le terminal et observez le résultat.
    L'exécution en avant-plan du processus emacs empêche l'exécution de tout autre processus lancé depuis ce terminal.
    La commande ls ne donne donc aucun résultat puisqu'elle n'est pas exécutée !
  3. Dans le terminal, tapez control+z pour stopper le processus en avant-plan (sans le détruire) et ainsi pouvoir utiliser le terminal.
    $ emacs ls ^Z [1]+ Stoppé emacs $
  4. Dans le terminal, vérifiez que vous pouvez exécuter la commande ls. Dans la fenêtre emacs, tapez quelques caractères pour vérifier son fonctionnement.
    La commande ls est bien exécutée.
    $ ls exo_manipulation_processus.php exo_manipulation_processus.php~ exo_observation_processus.php TP5 TP5.php
    La fenêtre emacs, par contre, ne répond pas (puisque le processus emacs est stoppé).
  5. Lancez la commande ps -l pour identifier le processus qui s'exécute et connaître l'état des autre processus lancés depuis ce terminal. Consultez la documentation de la commande ps pour trouver cette information (section « Codes d'état de processus », ou « Process state codes »).
    $ ps -l F S UID PID PPID C PRI NI ADDR SZ WCHAN TTY TIME CMD 0 S 1000 28837 20963 0 80 0 - 6343 - pts/4 00:00:00 bash 0 T 1000 32394 28837 5 80 0 - 127865 - pts/4 00:00:00 emacs 0 R 1000 32402 28837 0 80 0 - 9315 - pts/4 00:00:00 ps
    Le processus associé à la commande ps -l est en cours d'exécution ou peut s'exécuter (R).
    Le processus emacs est en attente (T).
    Les autres processus sont dormants (S) (en attente d'un d'événement).
  6. Tapez la commande fg pour relancer le processus emacs en avant-plan. Pouvez-vous maintenant écrire dans la fenêtre emacs ? Dans le terminal ?
    $ fg emacs
    La fenêtre emacs est maintenant utilisable. Mais le terminal est à nouveau bloqué.
    Le processus emacs est repassé en avant-plan et empêche le lancement de tout autre processus depuis le terminal.

Lancement en arrière-plan

  1. Si ce n'est pas déjà fait, tapez la commande emacs pour lancer, en avant-plan, le processus emacs
    $ emacs
  2. Dans le terminal, tapez control+z afin de suspendre le processus emacs. Vérifiez avec ps que le processus emacs est bien suspendu.
    ^Z [1]+ Stoppé emacs $ ps -l F S UID PID PPID C PRI NI ADDR SZ WCHAN TTY TIME CMD 0 T 1000 1127 28837 28 80 0 - 127855 - pts/4 00:00:00 emacs 0 R 1000 1143 28837 0 80 0 - 9315 - pts/4 00:00:00 ps 0 S 1000 28837 20963 0 80 0 - 6343 - pts/4 00:00:00 bash
    L'état du processus emacs (T) montre que celui-ci est bien suspendu.
  3. Tapez la commande bg pour relancer le processus emacs en arrière-plan. Pouvez-vous maintenant écrire dans la fenêtre emacs ? Dans le terminal ? Quelle est la différence entre les commandes fg et bg ?
    $ bg [1]+ emacs &
    La fenêtre emacs ainsi que le terminal sont maintenant utilisables. Les commandes fg et bg relancent toutes les deux un processus suspendu, mais fg le relance en avant-plan (et donc, « bloque » le terminal) alors que bg le relance en arrière-plan (et donc, le terminal reste utilisable).
  4. Utilisez la commande ps pour afficher l'état du processus emacs.
    $ ps -l F S UID PID PPID C PRI NI ADDR SZ WCHAN TTY TIME CMD 0 S 1000 1127 28837 0 80 0 - 127855 - pts/4 00:00:00 emacs 0 R 1000 1921 28837 0 80 0 - 9315 - pts/4 00:00:00 ps 0 S 1000 28837 20963 0 80 0 - 6343 - pts/4 00:00:00 bash
    Le processus emacs est bien dans l'état S (il attends que l'utilisateur saisisse quelquechose au clavier)
  5. Fermez le programme emacs, puis relancez-le en terminant la ligne de commande par & : emacs &. Vérifiez que le terminal reste utilisable. Vérifier avec ps que l'état du processus emacs est le même qu'à la question précédente.
    $ emacs & [1] 2047 $ ps -l F S UID PID PPID C PRI NI ADDR SZ WCHAN TTY TIME CMD 0 S 1000 2047 28837 1 80 0 - 127828 - pts/4 00:00:00 emacs 0 R 1000 2083 28837 0 80 0 - 9315 - pts/4 00:00:00 ps 0 S 1000 28837 20963 0 80 0 - 6343 - pts/4 00:00:00 bash
    Lancer le programme avec la commande emacs & est donc équivalent au lancement sans & suivi de la commande bg.
  6. Lors du lancement du processus emacs à la question précédente, deux nombres sont apparus sur le terminal. À quoi correspondent-ils ?
    $ emacs & [1] 2047
    Le nombre 1 correspond au numéro de job du processus créé en arrière-plan.
    Le nombre 2047 correspond au PID du processus créé. Cela se vérifie avec la commande ps :
    $ ps -l F S UID PID PPID C PRI NI ADDR SZ WCHAN TTY TIME CMD 0 S 1000 2047 28837 1 80 0 - 127828 - pts/4 00:00:00 emacs 0 R 1000 2083 28837 0 80 0 - 9315 - pts/4 00:00:00 ps 0 S 1000 28837 20963 0 80 0 - 6343 - pts/4 00:00:00 bash

Tuer des processus (∼15mn)

Tuer un processus

  1. Lancez 2 processus xeyes en arrière-plan.
    $ xeyes & [1] 15170 $ xeyes & [2] 15171
  2. Retrouvez le PID du premier processus xeyes lancé et utilisez la commande kill pour le détruire.
    Le PID du processus a été affiché lors du lancement du programme ([1] 15170). On peut également le retrouver avec la commande ps :
    $ ps PID TTY TIME CMD 5535 pts/2 00:00:00 bash 15170 pts/2 00:00:00 xeyes 15171 pts/2 00:00:00 xeyes 15233 pts/2 00:00:00 ps
    Pour tuer le processus :
    $ kill 15170
  3. Vérifiez que le processus n'existe plus.
    $ ps PID TTY TIME CMD 5535 pts/2 00:00:00 bash 15171 pts/2 00:00:00 xeyes 15271 pts/2 00:00:00 ps [1]- Complété xeyes
    Le processus xeyes de PID 15170 n'apparaît plus. De plus, le message ''[1]- Complété xeyes'' (indiquant que le job numéro 1 s'est terminé) est affiché.

Tuer plusieurs processus

  1. Relancez un processus xeyes en arrière-plan et vérifiez qu'il existe bien 2 processus xeyes.
    $ xeyes & [3] 15343 $ ps PID TTY TIME CMD 5535 pts/2 00:00:00 bash 13658 pts/2 00:00:25 emacs 15171 pts/2 00:00:02 xeyes 15343 pts/2 00:00:00 xeyes 15477 pts/2 00:00:00 ps
  2. Utilisez la commande killall pour terminer tous les processus xeyes en cours d'exécution.
    $ killall xeyes [2]- Complété xeyes [3]+ Complété xeyes

Chaîne de processus (∼1h15)

Cet exercice a pour but de vous apprendre à créer plusieurs processus en utilisant un algorithme récursif. Comme présenté sur la figure qui suit, vous allez créer une chaîne de N processus. Dans une chaîne de processus, chaque processus est le père du suivant, sauf pour le dernier processus de la chaîne, qui lui, n'a pas de fils. Le premier processus de la chaîne est appelé le processus initial et le dernier le processus final. Les autres processus sont appelés les processus intermédiaires.
pas d'image, désolé !

L'algorithme que nous utilisons est récursif. Si N vaut 1, alors l'unique processus de la chaîne est le processus final. Il ne doit donc rien faire de spécial. Si N est strictement supérieur à 1, alors le processus doit encore créer N-1 processus. Pour cela, il lui suffit de lancer chaine.sh avec comme paramètre N-1.

Nous allons écrire le script qui crée une chaîne de processus étape par étape. Pour commencer, écrivez un script nommé chaine.sh qui :
  • Vérifie ses arguments. Si le script ne reçoit pas un unique argument, il doit quitter avec un message d'erreur et un code de retour faux.
  • Affiche le message « Processus X démarre », où X est le PID du processus.
  • Quitte avec un code de retour vrai.

Avant de créer récursivement les processus, dans cette question, nous affichons ce que l'algorithme est supposé faire. Modifier votre script de façon à ce que :
  • si N est strictement supérieur à 1, votre script affiche « Il reste K processus à créer », où K est égal à N-1,
  • sinon, votre script affiche « Fin de chaîne ».

Nous finalisons maintenant l'algorithme. Après avoir affiché « Il reste K processus à créer », où K=N-1, votre script doit donc lancer la commande ./chaine.sh K pour créer le processus suivant de la chaîne.

Vérifiez que vous démarrez bien 4 processus lorsque vous invoquez ./chaine.sh 4.
$ chaine.sh 4 Processus 41732 démarre Il reste 3 processus à créer Processus 41734 démarre Il reste 2 processus à créer Processus 41736 démarre Il reste 1 processus à créer Processus 41738 démarre Fin de chaîne

Il faut maintenant lancer les processus en tâche de fond. Un processus ne doit aussi se terminer que lorsque son fils direct est terminé. Enfin, tous les processus (y compris le processus final) doivent afficher Processus X termine, où X est le PID du processus courant. Pour les processus qui possèdent un fils, cet affichage doit avoir lieu après avoir attendu la fin du fils.

Modifiez votre script en conséquence. Vérifiez aussi que les messages de terminaison s'affichent dans l'ordre inverse des créations en lançant ./chaine.sh 4.
$ ./chaine.sh 4 Processus 41929 démarre Il reste 3 processus à créer Processus 41931 démarre Il reste 2 processus à créer Processus 41933 démarre Il reste 1 processus à créer Processus 41935 démarre Fin de chaîne Processus 41935 termine Processus 41933 termine Processus 41931 termine Processus 41929 termine

Nous souhaitons maintenant communiquer le PID du processus initial jusqu'au processus final. Le langage bash fournit un mécanisme pour connaître le PID de son parent direct, mais pas de ses autres aïeuls. Il faut donc communiquer ce PID via un nouveau mécanisme. Pour mettre en œuvre un tel mécanisme, nous devons résoudre deux sous-problèmes :
  • Il faut être capable de communiquer le PID du processus initial jusqu'au processus final. Pour cela, nous utilisons une variable nommée pidInitial, initialisée par le processus initial à son PID, et exportée jusqu'au processus final.
  • Il faut que le processus initial soit capable de se reconnaître de façon à initialiser et exporter cette variable pidInitial. Tous les processus, sauf le processus initial, vont démarrer avec une copie de la variable pidInitial puisque cette dernière est exportée par le processus initial. Le processus initial est donc l'unique processus pour lequel la variable pidInitial n'est pas définie initialement, c.-à-d., pour lequel la variable pidInitial a pour valeur la chaîne de caractère vide, qui se reconnaît avec la construction [ -z "$pidInitial" ]).

Modifiez votre script de façon à ce que le processus initial initialise et exporte la variable pidInitial. Pour vous assurer que votre programme est correct, modifiez aussi l'affichage « Processus X démarre », où X est le PID du processus courant, en « Processus X démarre avec le processus initial Y », où Y est le PID du processus initial. Testez votre programme en lançant ./chaine.sh 4.
$ ./chaine.sh 4 Processus 42814 démarre avec le processus initial 42814 Il reste 3 processus à créer Processus 42816 démarre avec le processus initial 42814 Il reste 2 processus à créer Processus 42818 démarre avec le processus initial 42814 Il reste 1 processus à créer Processus 42820 démarre avec le processus initial 42814 Fin de chaîne Processus 42820 termine Processus 42818 termine Processus 42816 termine Processus 42814 termine
Félicitation ! Vous venez d'écrire votre première application multi-processus complexe !
Mettez le script chaine.sh de côté, vous vous en servirez à la prochaine séance.

Chasse au trésor – (∼30mn – hors présentiel)

Cet exercice nécessite un Linux et il n'est actuellement pas possible de le faire avec un Mac OS.
De retour de vacances, Bilbon décide de reprendre ses notes concernant la généalogie du nain Gimli. Au milieu de ses dossiers, il retrouve le programme genealogie qui, d'après ses souvenirs, permet de modéliser l'arbre généalogique du célèbre nain.

Mise en place de la chasse au trésor

  1. Récupérez l'archive contenant les notes de Bilbon mise à votre disposition ici. Comme pour le TP précédent, vous pouvez utiliser la commande wget.
    $ wget https://www-inf.telecom-sudparis.eu/COURS/CSC3102/Supports/ci5-processus/exo-chasse-au-tresor/tresor.tgz
    Si vous êtes sous MacOS, la commande wget n'est toujours pas pas installée par défaut. En remplacement, utilisez curl comme ci-dessous :
    $ curl https://www-inf.telecom-sudparis.eu/COURS/CSC3102/Supports/ci5-processus/exo-chasse-au-tresor/tresor.tgz --output tresor.tgz
  2. Extrayez l'archive dans votre arborescence.
    $ tar xzvf tresor.tgz
  3. Déplacez vous dans le répertoire ainsi créé et lancez la commande make.
    Vous aurez peut-être besoin d'installer auparavant gcc et make : sudo apt install gcc make.
    $ cd tresor $ make make -C nains make[1]: Entering directory '/tmp/tresor/nains' cc -O0 -g -Wall -lrt balin.c -o balin cc -O0 -g -Wall -lrt durin.c -o durin cc -O0 -g -Wall -lrt dwalin.c -o dwalin cc -O0 -g -Wall -lrt farin.c -o farin cc -O0 -g -Wall -lrt fudin.c -o fudin cc -O0 -g -Wall -lrt gimli.c -o gimli cc -O0 -g -Wall -lrt gloin.c -o gloin cc -O0 -g -Wall -lrt groin.c -o groin cc -O0 -g -Wall -lrt thorin.c -o thorin cc -O0 -g -Wall -lrt oin.c -o oin make[1]: Leaving directory '/tmp/tresor/nains' cc -o genealogie genealogie.c

La chasse au trésor

  1. Dans un terminal, lancez le programme genealogie. Préparez un autre terminal pour lancer des commandes pour répondre aux questions.
    $ ./genealogie
  2. Vous êtes accueillis par Gimli qui va vous aider à mettre en ordre les notes de Bilbon sur sa généalogie. Dans un premier temps, aidez-le à retrouver la fiche concernant son père.
    Retrouvez le PPID du processus gimli.
    $ pstree -p [...] ├─gnome-terminal-(1924)─┬─bash(1928)───emacs(7172)─┬─{dconf worker}(7175) │ │ ├─{gdbus}(7174) │ │ └─{gmain}(7173) │ ├─bash(3918)───genealogie(7347)───durin(7348)───thorin(7349)───farin(7350)─┬─fudin(7351)─┬─balin(7356) │ │ │ └─dwalin(7354) │ │ └─groin(7352)─┬─gloin(7353)───gimli(7357) │ │ └─oin(7355) [...]
    Autre solution:
    $ ps -el F S UID PID PPID C PRI NI ADDR SZ WCHAN TTY TIME CMD [...] 0 S 1000 7357 7353 0 80 0 - 2083 - pts/1 00:00:00 gimli
  3. Gimli se rend compte d'une erreur dans la fiche de son père qui ne mentionne pas sa mort. Corrigez cela dans le programme de généalogie.
    Tuez le processus père du processus gimli.
    $ kill 7353 # (où 7353 correspond au PPID de gimli)
  4. Vous êtes interrompus dans vos recherche par Oin, l'oncle de Gimli, qui annonce l'heure du goûter. Mais un des nains de la famille se goinfre et est en train de manger toutes les tartes. Retrouvez celui qui s'empiffre.
    Trouvez le PID du processus qui consomme beaucoup de CPU.
    $ top top - 11:37:48 up 2:33, 3 users, load average: 0,96, 0,53, 0,31 Tasks: 197 total, 2 running, 195 sleeping, 0 stopped, 0 zombie %Cpu(s): 3,7 us, 1,8 sy, 0,1 ni, 94,2 id, 0,2 wa, 0,0 hi, 0,0 si, 0,0 st KiB Mem : 8084284 total, 4543160 free, 1068476 used, 2472648 buff/cache KiB Swap: 10157052 total, 10157052 free, 0 used. 6714452 avail Mem PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND 7354 trahay 20 0 8320 724 628 R 93,8 0,0 2:52.41 dwalin [...]
    Il s'agit donc du processus 7354 (dwalin)
  5. Afin que les autres nains puissent participer au goûter, ils décident de punir le responsable en le mettant tout au bout de la table, loin des tartes.
    Donnez la priorité 17 au processus glouton.
    $ renice -n 17 7354 7354 (process ID) priorité précédente 0, nouvelle priorité 17
  6. Une fois le glouton puni, le goûter se déroule dans un calme relatif. Mais Gimli sonne la fin de la pause. Il est en effet l'heure de partir à la taverne. Mais les chevaux sont enfermés à clé dans l'écurie. La clé a été confiée à Balin qui a oublié où il l'avait rangé. Il a pourtant noté sur un bout de papier l'endroit où est rangée la clé...
    Trouvez le deuxième paramètre qui a été passé au processus balin à son lancement. Selon la méthode utilisée, vous devrez peut-être lancer emacs ou équivalent pour voir les séparateurs des arguments, représentés par ^@.
    $ ps -e [...] 7356 pts/1 00:00:00 balin
    Le répertoire /proc/7356 contient donc des informations sur le processus balin.
    $ emacs /proc/7356/cmdline balin^@abcdefghijklmnopqrstuvwxyzabcdefg[...]zabcdefghijklmnopqrstuvwxyz^@chaussette^@
    La réponse est donc 'chaussette' !
    Balin retrouve finalement la clé au fond de sa chaussette (il y avait bien quelque chose qui lui faisait mal au pied !)
  7. Les nains peuvent donc ouvrir l'écurie et se rendre à la taverne. Pendant que les nains festoient, Bilbon se désole du peu d'avancement de ses recherches...
Pour les besoins de l'exercice, la généalogie exacte de Gimli a dû être altérée. Toute l'équipe enseignante prie les puristes du Seigneur des Anneaux de l'en excuser.

Concurrence (∼30mn – défi)

Le programme calcul.c effectue un calcul parfaitement inutile, mais qui a le mérite d'être très régulier (le programme effectue un nombre d'instructions fixe d'une exécution à l'autre pour une même entrée). Téléchargez ce programme en cliquant ici, ou avec wget :
$ wget https://www-inf.telecom-sudparis.eu/COURS/CSC3102/Supports/ci5-processus/exo-concurrence/calcul.c
Si vous êtes sous MacOS, la commande wget n'est toujours pas pas installée par défaut. En remplacement, utilisez curl comme ci-dessous :
$ curl https://www-inf.telecom-sudparis.eu/COURS/CSC3102/Supports/ci5-processus/exo-concurrence/calcul.c --output calcul.c

Pour compiler le programme, lancer la commande « gcc -o calcul calcul.c ».

Une fois le programme compilé, vérifiez la présence du fichier exécutable calcul dans votre répertoire et lancez le programme calcul avec le paramètre 60000. Observez le temps nécessaire au calcul.
$ ./calcul 60000 [425] Début du calcul jusqu'à 60000. Ma priorité: 0 [425] Le résultat: 2079112224. Calculé en 4564.65 ms. Ma priorité: 0

Les machines de la salle de TP sont équipées de processeurs multicœurs. Cela veut dire que la machine contient plusieurs « processeurs » et peut donc exécuter plusieurs programmes simultanément.

Utilisez la commande lscpu pour trouver le nombre de cœurs de votre machine (voir la ligne commençant par « Proc »).
$ lscpu | grep Proc Processeur(s) : 2

Ecrivez un script calcul_parallele.sh qui exécute NCPU fois la commande ./calcul 60000 en arrière-plan, NCPU étant le nombre de CPU de la machine trouvé à la question précédente.

Exécutez le script calcul_parallele.sh et observez le temps d'exécution des différents processus. La variation d'un processus à l'autre est-elle grande ?
$ ./calcul_parallele.sh [427] Début du calcul jusqu'à 60000. Ma priorité: 0 [429] Début du calcul jusqu'à 60000. Ma priorité: 0 [427] Le résultat: 2079112224. Calculé en 4936.80 ms. Ma priorité: 0 [429] Le résultat: 2079112224. Calculé en 4943.09 ms. Ma priorité: 0
Le temps d'exécution varie peu d'un processus à l'autre. Le temps d'exécution n'a que peu augmenté par rapport à la question précédente car aucun processeur n'est saturé.

Modifiez maintenant le script calcul_parallele.sh pour qu'il exécute N+1 fois la commande ./calcul 60000 en arrière-plan. Exécutez le script. Que remarquez vous ?
$ ./calcul_parallele.sh [432] Début du calcul jusqu'à 60000. Ma priorité: 0 [436] Début du calcul jusqu'à 60000. Ma priorité: 0 [434] Début du calcul jusqu'à 60000. Ma priorité: 0 [436] Le résultat: 2079112224. Calculé en 7680.33 ms. Ma priorité: 0 [434] Le résultat: 2079112224. Calculé en 7710.24 ms. Ma priorité: 0 [432] Le résultat: 2079112224. Calculé en 7883.47 ms. Ma priorité: 0
On remarque que le temps d'exécution a fortement augmenté par rapport à la question précédente. Cela s'explique par l'embouteillage pour accèder au processeur : comme il y a plus de processus que de processeurs, les processus doivent se partager les processeurs et sont donc ralentis. On remarque aussi que tous les processus prennent à peu près le même temps.

Modifiez le script calcul_parallele.sh afin que l'un des processus soit lancés avec la priorité 19.

Exécutez le script calcul_parallele.sh. Que pouvez-vous conclure ?
$ ./calcul_parallele.sh [439] Début du calcul jusqu'à 60000. Ma priorité: 0 [443] Début du calcul jusqu'à 60000. Ma priorité: 0 [441] Début du calcul jusqu'à 60000. Ma priorité: 19 [443] Le résultat: 2079112224. Calculé en 5024.99 ms. Ma priorité: 0 [439] Le résultat: 2079112224. Calculé en 5107.91 ms. Ma priorité: 0 [441] Le résultat: 2079112224. Calculé en 9476.70 ms. Ma priorité: 19
On remarque que le processus de priorité 19 s'exécute beaucoup plus lentement que les processus de priorité 0. Par rapport à la question précédente, on remarque aussi que le processus moins prioritaire gêne moins les autres processus, mais qu'il est beaucoup plus ralenti.

Modifiez le script calcul_parallele.sh de façon à démarrer N+1 processus de calcul avec la priorité 0, puis à changer, au bout de 3 secondes, la priorité de l'un des processus. Exécutez le script et vérifiez que vous avez bien le comportement attendu.
Vous aurez besoin de connaître le PID d'un des processus fils pour changer sa priorité. Pour cela, vous devez savoir que la variable $! est égale au PID du dernier processus lancé en arrière-plan. Par exemple:
$ xeyes & [1] 9645 $ echo $! 9645 $
$ ./calcul_parallele.sh [446] Début du calcul jusqu'à 60000. Ma priorité: 0 [448] Début du calcul jusqu'à 60000. Ma priorité: 0 [450] Début du calcul jusqu'à 60000. Ma priorité: 0 450 (process ID) priorité précédente 0, nouvelle priorité 19 [448] Le résultat: 2079112224. Calculé en 6043.25 ms. Ma priorité: 0 [446] Le résultat: 2079112224. Calculé en 6255.58 ms. Ma priorité: 0 [450] Le résultat: 2079112224. Calculé en 8756.52 ms. Ma priorité: 19
Tous les processus démarrent bien avec la même priorité de 0. Un des processus voit bien sa priorité passer à 19 au bout de 3s. Ce changement de priorité au bout de 3 secondes a un impact sur les durées d'exécution: le processus le moins prioritaire est significativement plus lent que les processus prioritaires. Quand on compare ce résultat à celui de la question précédente, on voit que les processus prioritaires sont plus lents que dans la question précédente, et que le processus moins prioritaire est plus rapide que dans la question précédente. C'est normal, puisque dans cet exercice, le processus moins prioritaire est tout de même aussi prioritaire que les autres processus pendant les 3 premières secondes.