Go to file
2023-10-19 10:34:17 +02:00
TP1 Changement de disposition 2023-09-14 15:12:21 +02:00
TP2 Finalisation de l'exo 4 2023-09-15 18:06:23 +02:00
TP3 Correction 2023-10-19 10:34:17 +02:00
TP4 Ajout de l'exo3 TP4 2023-10-12 09:39:37 +02:00
TP5 Ajout de l'exo 2 TP5 2023-10-11 15:10:22 +02:00
TP6 Ajout exo 2 TP6 2023-10-13 15:57:13 +02:00
README.md Ajout de l'exo 1 TP6 2023-10-12 22:46:12 +02:00

TP 1 : Mémoire

Exercice 1

Soit le programme suivant qui affiche les adresses virtuelles de certaines variables lors de l'exécution du processus. En utilisant le (pseudo) fichier /proc/pid/maps, vérifiez à quel segment de pages ces adresses appartiennent.

tom@Error404:/mnt/c/Users/naser/Documents/scr/TP1$ ./adresses_virtuelles

mon pid est 20

main    =       0x564bfc70e169
&argc   =       0x7ffd8f4ac78c
&i      =       0x7ffd8f4ac794
&j      =       0x564bfc711fe0
t       =       0x564bfc711040
m       =       0x564bfd7e62a0
tom@Error404:/mnt/c/Users/naser/Documents/scr/TP1$ cat /proc/20/maps 
564bfc70d000-564bfc70e000 r--p 00000000 00:48 3659174697600603           /mnt/c/Users/naser/Documents/scr/TP1/adresses_virtuelles
564bfc70e000-564bfc70f000 r-xp 00001000 00:48 3659174697600603           /mnt/c/Users/naser/Documents/scr/TP1/adresses_virtuelles
564bfc70f000-564bfc710000 r--p 00002000 00:48 3659174697600603           /mnt/c/Users/naser/Documents/scr/TP1/adresses_virtuelles
564bfc710000-564bfc711000 r--p 00002000 00:48 3659174697600603           /mnt/c/Users/naser/Documents/scr/TP1/adresses_virtuelles
564bfc711000-564bfc712000 rw-p 00003000 00:48 3659174697600603           /mnt/c/Users/naser/Documents/scr/TP1/adresses_virtuelles
564bfd7e6000-564bfd807000 rw-p 00000000 00:00 0                          [heap]
7f246a43d000-7f246a440000 rw-p 00000000 00:00 0
7f246a440000-7f246a466000 r--p 00000000 08:20 10783                      /usr/lib/x86_64-linux-gnu/libc.so.6
7f246a466000-7f246a5bb000 r-xp 00026000 08:20 10783                      /usr/lib/x86_64-linux-gnu/libc.so.6
7f246a5bb000-7f246a60e000 r--p 0017b000 08:20 10783                      /usr/lib/x86_64-linux-gnu/libc.so.6
7f246a64e000-7f246a658000 r--p 00026000 08:20 10780                      /usr/lib/x86_64-linux-gnu/ld-linux-x86-64.so.2
7f246a658000-7f246a65a000 r--p 00030000 08:20 10780                      /usr/lib/x86_64-linux-gnu/ld-linux-x86-64.so.2
7f246a65a000-7f246a65c000 rw-p 00032000 08:20 10780                      /usr/lib/x86_64-linux-gnu/ld-linux-x86-64.so.2
7ffd8f48e000-7ffd8f4af000 rw-p 00000000 00:00 0                          [stack]
7ffd8f568000-7ffd8f56c000 r--p 00000000 00:00 0                          [vvar]
7ffd8f56c000-7ffd8f56e000 r-xp 00000000 00:00 0                          [vdso]
main appartient au deuxieme segment de pages (564bfc70e000-564bfc70f000)
&argc appartient au stack (7ffd8f48e000-7ffd8f4af000)
&i appartient aussi au stack (7ffd8f48e000-7ffd8f4af000)
&j appartient au heap (564bfd7e6000-564bfd807000)
t appartient au heap (564bfd7e6000-564bfd807000)
m appartient au heap (564bfd7e6000-564bfd807000)

Exercice 1 bis

L'interface (pseudo-fichier) proc/pid/smaps permet de voir la consommation mémoire d'un processus. On peut le formater avec la commande pmap -X. Le but de l'exercice est de voir ce qui se passe au niveau de la mémoire d'un processus suivant les différents mode d'allocation. Le programme null.c permet d'avoir un point de comparaison. Dans les cas suivants, vérifiez où se trouve la memoire correspondante :

  1. Allocation statique buf.c
tom@Error404:/mnt/c/Users/naser/Documents/scr/TP1/Exo1/ex1bis$ pmap -x 51
51:   ./buf
Address           Kbytes     RSS   Dirty Mode  Mapping
000055a1b721c000       4       4       0 r---- buf
000055a1b721d000       4       4       0 r-x-- buf
000055a1b721e000       4       4       0 r---- buf
000055a1b721f000       4       4       4 r---- buf
000055a1b7220000       4       4       4 rw--- buf
000055a1b7221000   24576   16516   16516 rw---   [ anon ]
000055a1b986a000     132       4       4 rw---   [ anon ]
00007f52d26db000      12       8       8 rw---   [ anon ]
00007f52d26de000     152     152       0 r---- libc.so.6
00007f52d2704000    1364     860       0 r-x-- libc.so.6
00007f52d2859000     332     108       0 r---- libc.so.6
00007f52d28ac000      16      16      16 r---- libc.so.6
00007f52d28b0000       8       8       8 rw--- libc.so.6
00007f52d28b2000      52      20      20 rw---   [ anon ]
00007f52d28c4000       8       4       4 rw---   [ anon ]
00007f52d28c6000       4       4       0 r---- ld-linux-x86-64.so.2
00007f52d28c7000     148     148       0 r-x-- ld-linux-x86-64.so.2
00007f52d28ec000      40      36       0 r---- ld-linux-x86-64.so.2
00007f52d28f6000       8       8       8 r---- ld-linux-x86-64.so.2
00007f52d28f8000       8       8       8 rw--- ld-linux-x86-64.so.2
00007ffc3f565000     132      12      12 rw---   [ stack ]
00007ffc3f5a8000      16       0       0 r----   [ anon ]
00007ffc3f5ac000       8       4       0 r-x--   [ anon ]
---------------- ------- ------- -------
total kB           27036   17936   16612

L'allocation statique de buf.c se trouve à l'adresse 000055a1b7221000 et elle est de 24576 Kbytes

  1. Allocation sur la pile stack.c
tom@Error404:/mnt/c/Users/naser/Documents/scr/TP1/Exo1/ex1bis$ pmap -x 57
57:   ./stack
Address           Kbytes     RSS   Dirty Mode  Mapping
000055c5f583a000       4       4       0 r---- stack
000055c5f583b000       4       4       0 r-x-- stack
000055c5f583c000       4       4       0 r---- stack
000055c5f583d000       4       4       4 r---- stack
000055c5f583e000       4       4       4 rw--- stack
000055c5f5acb000     132       4       4 rw---   [ anon ]
00007f019bcba000      12       8       8 rw---   [ anon ]
00007f019bcbd000     152     152       0 r---- libc.so.6
00007f019bce3000    1364     804       0 r-x-- libc.so.6
00007f019be38000     332     112       0 r---- libc.so.6
00007f019be8b000      16      16      16 r---- libc.so.6
00007f019be8f000       8       8       8 rw--- libc.so.6
00007f019be91000      52      20      20 rw---   [ anon ]
00007f019bea3000       8       4       4 rw---   [ anon ]
00007f019bea5000       4       4       0 r---- ld-linux-x86-64.so.2
00007f019bea6000     148     148       0 r-x-- ld-linux-x86-64.so.2
00007f019becb000      40      36       0 r---- ld-linux-x86-64.so.2
00007f019bed5000       8       8       8 r---- ld-linux-x86-64.so.2
00007f019bed7000       8       8       8 rw--- ld-linux-x86-64.so.2
00007ffdebac4000     132      36      36 rw---   [ stack ]
00007ffdebbef000      16       0       0 r----   [ anon ]
00007ffdebbf3000       8       4       0 r-x--   [ anon ]
---------------- ------- ------- -------
total kB            2460    1392     120

L'allocation sur la pile de stack.c se trouve à l'adresse 00007ffdebac4000 et elle est de 132 Kbytes

  1. Allocation sur le tas heap.c
tom@Error404:/mnt/c/Users/naser/Documents/scr/TP1/Exo1/ex1bis$ pmap -x 59
59:   ./heap
Address           Kbytes     RSS   Dirty Mode  Mapping
000055ac09aae000       4       4       0 r---- heap
000055ac09aaf000       4       4       0 r-x-- heap
000055ac09ab0000       4       4       0 r---- heap
000055ac09ab1000       4       4       4 r---- heap
000055ac09ab2000       4       4       4 rw--- heap
000055ac0a4c2000   50028   49924   49924 rw---   [ anon ]
00007f1e58321000      12       8       8 rw---   [ anon ]
00007f1e58324000     152     152       0 r---- libc.so.6
00007f1e5834a000    1364     844       0 r-x-- libc.so.6
00007f1e5849f000     332      64       0 r---- libc.so.6
00007f1e584f2000      16      16      16 r---- libc.so.6
00007f1e584f6000       8       8       8 rw--- libc.so.6
00007f1e584f8000      52      20      20 rw---   [ anon ]
00007f1e5850a000       8       4       4 rw---   [ anon ]
00007f1e5850c000       4       4       0 r---- ld-linux-x86-64.so.2
00007f1e5850d000     148     148       0 r-x-- ld-linux-x86-64.so.2
00007f1e58532000      40      36       0 r---- ld-linux-x86-64.so.2
00007f1e5853c000       8       8       8 r---- ld-linux-x86-64.so.2
00007f1e5853e000       8       8       8 rw--- ld-linux-x86-64.so.2
00007ffe0d57b000     132      12      12 rw---   [ stack ]
00007ffe0d5fa000      16       0       0 r----   [ anon ]
00007ffe0d5fe000       8       4       0 r-x--   [ anon ]
---------------- ------- ------- -------
total kB           52356   51280   50016

L'allocation sur le tas de heap.c se trouve à l'adresse 000055ac0a4c2000 et elle est de 50028 Kbytes

  1. Allocation (gande quantité) sur le tas huge.c
tom@Error404:/mnt/c/Users/naser/Documents/scr/TP1/Exo1/ex1bis$ pmap -x 61
61:   ./huge
Address           Kbytes     RSS   Dirty Mode  Mapping
000055fdf6259000       4       4       0 r---- huge
000055fdf625a000       4       4       0 r-x-- huge
000055fdf625b000       4       4       0 r---- huge
000055fdf625c000       4       4       4 r---- huge
000055fdf625d000       4       4       4 rw--- huge
000055fdf6cef000     132     100     100 rw---   [ anon ]
00007f5bb5f2e000     272     268     268 rw---   [ anon ]
00007f5bb5f72000     152     152       0 r---- libc.so.6
00007f5bb5f98000    1364     852       0 r-x-- libc.so.6
00007f5bb60ed000     332      64       0 r---- libc.so.6
00007f5bb6140000      16      16      16 r---- libc.so.6
00007f5bb6144000       8       8       8 rw--- libc.so.6
00007f5bb6146000      52      20      20 rw---   [ anon ]
00007f5bb6158000       8       4       4 rw---   [ anon ]
00007f5bb615a000       4       4       0 r---- ld-linux-x86-64.so.2
00007f5bb615b000     148     148       0 r-x-- ld-linux-x86-64.so.2
00007f5bb6180000      40      36       0 r---- ld-linux-x86-64.so.2
00007f5bb618a000       8       8       8 r---- ld-linux-x86-64.so.2
00007f5bb618c000       8       8       8 rw--- ld-linux-x86-64.so.2
00007fffa6cae000     132      16      16 rw---   [ stack ]
00007fffa6cf2000      16       0       0 r----   [ anon ]
00007fffa6cf6000       8       4       0 r-x--   [ anon ]
---------------- ------- ------- -------
total kB            2720    1728     456

L'allocation (gande quantité) sur le tas de huge.c se trouve à l'adresse 00007f5bb5f2e000 et elle est de 272 Kbytes

  1. Allocation sur le mapping mmap.c
tom@Error404:/mnt/c/Users/naser/Documents/scr/TP1/Exo1/ex1bis$ pmap -x 64
64:   ./mmap
Address           Kbytes     RSS   Dirty Mode  Mapping
000055c9d1054000       4       4       0 r---- mmap
000055c9d1055000       4       4       0 r-x-- mmap
000055c9d1056000       4       4       0 r---- mmap
000055c9d1057000       4       4       4 r---- mmap
000055c9d1058000       4       4       4 rw--- mmap
000055c9d2214000     132       4       4 rw---   [ anon ]
00007fad683c0000     256     128     128 rw--- 256k
00007fad68400000      64      64      64 rw-s- zero (deleted)
00007fad68410000      44      40      40 rw---   [ anon ]
00007fad6841b000     152     152       0 r---- libc.so.6
00007fad68441000    1364     812       0 r-x-- libc.so.6
00007fad68596000     332     120       0 r---- libc.so.6
00007fad685e9000      16      16      16 r---- libc.so.6
00007fad685ed000       8       8       8 rw--- libc.so.6
00007fad685ef000      52      20      20 rw---   [ anon ]
00007fad685fd000      24       4       4 rw---   [ anon ]
00007fad68603000       4       4       0 r---- ld-linux-x86-64.so.2
00007fad68604000     148     148       0 r-x-- ld-linux-x86-64.so.2
00007fad68629000      40      36       0 r---- ld-linux-x86-64.so.2
00007fad68633000       8       8       8 r---- ld-linux-x86-64.so.2
00007fad68635000       8       8       8 rw--- ld-linux-x86-64.so.2
00007ffdc2360000     132      16      16 rw---   [ stack ]
00007ffdc2384000      16       0       0 r----   [ anon ]
00007ffdc2388000       8       4       0 r-x--   [ anon ]
---------------- ------- ------- -------
total kB            2828    1612     324

L'allocation sur le mapping de mmap.c se trouve à l'adresse 00007fad683c0000 et elle est de 256 Kbytes

Exercice 2

Soit le programme suivant.

  1. Compilez le programme. Avec la commande size, regardez les différents segments du programme. Où se trouve le tableau t ? Augmentez la valeur de N. La taille de l'exécutable a-t-elle changé ? pourquoi ?

Le tableau t se trouve dans le segment .bss et la taille de l'exécutable n'a pas changé car le tableau t n'est pas initialisé.

  1. Recommencez avec la version 2. Expliquez.

Le tableau t se trouve dans le segment .data et la taille de l'exécutable a changé car le tableau t est initialisé.

Exercice 3

Soit le programme suivant. Le temps d'éxecution de ce programme est-il différent pour les deux versions ? Pourquoi ?

Le temps d'éxecution de ce programme est différent pour les deux versions car dans la première version, les éléments du tableau sont accédés de manière séquentielle, alors que dans la deuxième version, le cache est rempli car on lit les éléments du tableau par colonne, donc il y a plus de cache miss vu qu'on fait des incréments bien plus grands que dans la première version.

Exercice 4

Le programme sum_array.c fait la somme des éléments d'un tableau en accédant aux éléments séquentiellement (-c croissant, -d décroissant) ou de manière aléatoire (-a). Testez en faisant varier la taille du tableau. Expliquez.

La raison de pourquoi la manière aléatoire est plus lente que la manière croissante ou décroissante (qui sont aussi rapide l'une que l'autre), est que la manière aléatoire fait plus de cache miss que les deux autres, car elle accède aux éléments du tableau de manière aléatoire, donc il y a plus de chance que l'élément ne soit pas dans le cache, alors que dans les deux autres, les éléments sont accédés de manière séquentielle, donc il y a plus de chance que l'élément soit dans le cache. Ce qui force la lecture de la RAM.

Exercice 5

Ecrire une fonction

void hexdump(void * ptr,size_t size);

qui affiche sur la sortie standard le contenu de la mémoire [ptr,ptr+size[ au format :

XXXXXXXX  BB BB BB BB BB BB BB BB  BB BB BB BB BB BB BB BB  |CCCCCCCCCCCCCCCC|

(comme la commande shell)

  • XXXXXXXXX représente l'adresse du premier octet de la ligne
  • BB la valeur hexadécimale de chaque octet
  • |CCCCCCCCCCCCCCCC| la correspondance ascii de chaque octet (. si non affichable)

Est-ce conforme à ce que l'on a vu en cours concernant l'alignement en mémoire ?

L'alignement en mémoire est conforme à ce que l'on a vu en cours car les adresses sont alignées sur 16 octets.

TP 2 : Fichiers

Exercice 1

Écrire deux versions d'un programme qui copie "octet par octet" un fichier source dans un fichier destination :

./copy infile outfile

en utilisant :

  1. les appels systèmes linux : open, read, write, close.
  2. les fonctions E/S standards (sdtio) : fopen, fread, fwrite, fclose.

Testez vos deux programmes sur un fichier volumineux (utilisez la commande dd le pseudo fichier dev/urandom pour générer un contenu aléatoire) et expliquez pourquoi le deuxième programme est beaucoup plus rapide que le premier.

Remarque:

  • pour être dans les mêmes conditions, il faut être sur que le fichier à copier n'est pas en cache en mémoire. Générez un nouveau fichier de même taille, ou utilisez le programme fadvise.c qui permet de vider les blocs du cache pour un fichier quelconque.
  • utilisez strace pour tracer les appels systèmes de vos deux programmes.

Le deuxième programme est beaucoup plus rapide que le premier car il utilise des buffers, alors que le premier programme lit et écrit octet par octet et fait plus d'appels systèmes.

Exercice 2

Écrire un programme qui copie un fichier en utilisant mmap.

Exercice 3

Compilez et exécutez Le programme coherence.c. Qu'est ce que cela montre ?

Ce programme montre que quand nous lisons avec stdio, le contenu du fichier est mis en cache, et quand nous lisons avec read, il n'y a pas de cache, c'est pourquoi quand nous lisons avec stdio nous avons l'ancienne version du fichier, et quand nous lisons avec read nous avons la nouvelle version du fichier.

Exercice 4

Le but est d'écrire en C un programme qui efface un fichier du disque de telle manière que le contenu effacé ne soit pas récupérable. Pour des raisons physiques, on procédera de la manière suivante :

  • Si l'inode correspondant au fichier à effacer à plusieurs références, on efface juste l'entrée du répertoire correspondant.
  • Sinon, on réécrit les blocs de données :
    • une première passe avec 0xff pour tous les octets.
    • une deuxième passe avec des valeurs aléatoires (on utilisera le pseudo-fichier /dev/urandom)
    • enfin, avant d'effacer le fichier, on le renomera de manière aléatoire.

Toutes les E/S devront utilisées un cache.

TP 3 : Processus

Exercice 1

Compilez et exécutez ex1-stdio et ex1-syscall. Expliquez.

Avec stdio, le printf écrit "NON" dans le cache, c'est pourquoi lors de l'utilisation du fork le printf écrit "NON" deux fois, alors qu'avec syscall, le write écrit "NON" directement dans la sortie standard, c'est pourquoi lors de l'utilisation du fork le printf écrit "NON" une seule fois.

Exercice 2

Compilez et exécutez fork_and_fd1.c et fork_and_fd2.c. Expliquez.

Pour le premier programme, le fork est fait après l'ouverture du fichier, donc le père et le fils se partagent le même descripteur de fichier, si l'un écrit, l'offset va se mettre à jour pour que les deux écrivent à la suite. Pour le deuxième programme, le fork est fait avant l'ouverture du fichier, donc le père et le fils ont deux descripteurs de fichier différents, l'offset n'est pas partagé donc le contenu du fichier sera celui du dernier à écrire.

Exercice 3

Que fait le programme copy1byte.c ? Décommentez la ligne du fork. Expliquer ce qui se passe.

Le programme copy1byte.c copie le fichier source dans le fichier destination en utilisant des appels systèmes. Quand on décommente la ligne du fork, ce dernier est effectué après l'ouverture du fichier, donc le père et le fils ont deux descripteurs de fichier différents, l'offset n'est pas partagé donc le contenu du fichier sera celui du dernier à écrire.

Exercice 4

Ecrire un programme qui crée un processus fils.

Dans le fils :

  • imprimer le retour de fork(), getpid(), getppid().
  • bloquer 4 secondes (sleep).
  • se terminer avec exit(2).

Dans le père :

  • imprimer le retour de fork(), getpid(), getppid().
  • attendre la fin de son fils (wait()), et imprimer son code de retour.
  • afficher alors la liste de tous les processus actifs (execl() avec ps -ef).

Exercice 5

Le but de l'exercice est de détecter la présence d'un zéro dans un tableau unsigned char de taille SIZE en découpant le travail entre plusieurs processus.

Combien y-at-il de 0 au plus dans le tableau ? Complétez la fonction search, et testez.

  1. Première version. Modifiez le programme pour que le processus crée un fils. Le fils et le père cherche chacun le zéro dans une moitié du tableau. Le fils communique le résultat à son père. Celui-ci, à l'aide de son propre travail, donnera la réponse.

  2. Deuxième version. Votre programme accepte sur la ligne de commande un entier n entre 1 et 100. Le programme crée n fils qui cherche chacun dans une partie du tableau. Le père attend la fin de chacun de ses fils, récupère leur résultat et affiche la réponse.

  3. Troisième version. On améliore la version précédente. Lorsque qu'un fils trouve le 0 dans le tableau, et que le père en est averti, faites en sorte que les autres fils vivants se terminent. On utilisera la primitive kill() qui perment d'envoyer le signal de terminaison (SIGTERM) à tout un groupe.

Exercice 6

Exécutez le programme session.c et interprétez avec ps les informations pid,ppid,pgid,sess,tpgid des processus créés.

tom@Error404:/mnt/c/Users/naser/Documents/scr/r305_dm/TP3/Exo6$ ./session

session = 9
session = 8442
tom@Error404:/mnt/c/Users/naser/Documents/scr/r305_dm/TP3/Exo6$ ps -o pid,ppid,pgid,sess,tpgid
  
  PID  PPID  PGID  SESS TPGID
  103   102   103   103  8443
 8443   103  8443   103  8443

On peut voir qu'on a bien créé un processus fils, mais vu qu'on est pas leader de session on ne peut pas créer de nouvelle session, c'est pourquoi sess et tpgid sont les mêmes que le père.

Exercice 7

Écrire un programme qui pour n>0 donné sur la ligne de commande, engendre l'arbre généalogique :

0|
 |\ 1
 | \
 | |\ 2
 | | \
 | | |\ ...
 | | | \
 | | | |\ n
 x x x x x	

Chaque processus choisit un nombre au hasard entre 0 et 127. Le processus 0 affichera la plus grande valeur choisie par tous les processus.

Remarque : on pourra modifier la séquence de nombres aléatoires en utilisant srand dans chaque processus créé. (pourquoi ?)

TP 4 : Signaux

Exercice 1

Pour calculer le nombre pi, on utilise la méthode de Monte-Carlo. On tire aléatoirement des couples (x,y) de nombres de [0,1] x [0,1]. La probabilité qu'il tombe dans le disque de rayon 1 est exactement de pi/4. On procède à plusieurs tirages pour estimer la probilité correspondante.

En utilisant les signaux, mettre en place :

  • avec SIGALRM, toutes les 5 secondes, l'affichage de la valeur pi en cours et le nombre de tirs effectués.
  • avec SIGINT l'arrêt du programme (après la demande d'une confirmation), avec l'affichage du temps écoulé depuis son lancement, quand on fait ctrl+C au terminal.
  • avec SIGQUIT la réinitialisation du calcul avec ctrl+\ depuis le terminal. (faites en sorte que toutes les valeurs restent cohérentes)

Dans chaque handler, les 2 autres signaux seront bloqués.

Exercice 2

Écrire un programme mytimeout.c dont l'usage est

$mytimeout nbsec com [arg ...]
  • Il lance la commande com [arg ...] (fork-and-exec).
  • Il attend nbsec secondes, ou la fin de son fils.
  • Si la commande n'est pas encore terminée au bout de du temps, il lui envoie le signal SIGTERM.

En cas de terminaison de la commande, il renvoie son code de retour, sinon renvoie le code 124.

Exercice 3

Le but est de protéger un morceau de code d'un éventuellement déroutement à cause de la prise en compte d'un signal.

  1. Lancez le programme, et envoyez (depuis le terminal) le signal SIGQUIT souvent. La fonction swap est-elle interrompue ? comment le voyez-vous ?

On peut voir que la fonction swap est interrompue car quand nous envoyons le signal SIGQUIT souvent dans le terminal, le programme s'arrête pour afficher soit "x=2 y=2" soit "x=3 y=3", alors que si la fonction swap n'était pas interrompue, le programme afficherait soit "x=2 y=3" ou "x=3 y=2".

  1. Ajoutez le code nécessaire pour assurer que swap ne soit jamais interrompue par SIGQUIT.

Exercice 4

On va simuler un match de ping-pong entre un père et son fils, en utilisant le signal SIGUSR1.

  • Le père commence à jouer.

  • On simule 10 échanges. À chaque coup, le père affiche Ping, le fils Pong. L'envoie de la balle consiste à envoyer le signal SIGUSR1 à son adversaire.

La difficulté consiste à synchroniser correctement les échanges.

  1. Expliquez pourquoi ce code n'est pas correct (Faites varier N).

Ce code n'est pas correct car il n'y a pas de synchronisation entre le père et le fils, donc le père peut envoyer le signal SIGUSR1 au fils alors que le fils n'est pas encore en attente, ce qui fait que parfois le fils ne va pas recevoir le signal et donc ne va pas afficher Pong.

  1. Proposez une solution.

Pour synchroniser le père et le fils, on peut utiliser sigprocmask pour bloquer les signaux SIGUSR1 dans le père et le fils, et les débloquer quand on veut envoyer le signal SIGUSR1 au fils ou au père.

TP 5 : Redirections, tubes

Exercice 1

  1. Écrire un programme C pour calculer la taille du tampon système associé à un tube. (on pourra rendre l'écriture non bloquante avec fcntl)

  2. Écrire un programme C qui a le même comportement que la commande shell

ls -i -l /tmp >> log
  1. Écrire un programme C qui a le même comportement que la commande shell
ls . | wc -l

Exercice 2

Soit le graphe de processus suivant (un tube est établi entre Pf2 et Pf1f1)

	| P
	|____
	|    \  Pf1  
	|     \
	|      \
	|\Pf2  |\
	| \    | \Pf1f1
	|  \   |  \
	O   O  O   O
	    ()-->--()
  1. Ecrivez un programme pipe-ex.c qui implante le graphe ci-dessus (y compris le tube) et tel que :
  • Pf2 écrive en permanence toutes les 3 secondes son PID dans le tube en affichant ce qu'il écrit
  • Pf1f1 lise en permanence chaque seconde depuis tube sizeof(pid_t) en affichant ce qu'il lit

Vérifiez que le programme fonctionne comme prévu, i.e il affiche :

16411 sent 16411
	16412 received 16411
16411 sent 16411
	16412 received 16411
.....
  1. Lancez le programme ci-dessus et faites les essais suivants (relancez le programme après chaque essai). Expliquez à chaque fois vos observations.
  • Envoyez le signal SIGSTOP à Pf2, puis le signal SIGCONT à Pf2.

Le programme s'arrête d'écrire dans le tube, mais il continue de lire dans le tube sans afficher ce qu'il lit car il est bloqué en lecture.

  • Envoyez le signal SIGSTOP à Pf1f1, puis le signal SIGCONT à Pf1f1.

Le programme s'arrête de lire dans le tube, mais il continue d'écrire dans le tube.

  • Envoyez le signal SIGTERM à Pf2.
  • Envoyez le signal SIGTERM à Pf1f1.

Exercice 3

Voici un programme qui calcule le nième terme de la suite de Fibonacci de manière récursive (ce n'est pas la meilleure approche comme vous le savez).

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <assert.h>
long int fibo (long int n)
{
	return (n<=1)?n:fibo(n-1)+fibo(n-2);
}

int main(int argc, char *argv[])
{
	long int n;
	assert(argc > 1);
	n=strtol(argv[1],NULL,0);
	printf("fibo(%ld) = %ld\n",n,fibo(n));
	return 0;
}

L'arbre d'appel correspondant pour n=4 :

                       fibo(4)
                       /     \
                      /	      \
                fibo(2)        fibo(3)
               /     \        /     \
              /	      \      /       \
        fibo(0)    fibo(1) fibo(1) fibo(2)  
                                   /	\
                                  /      \ 
                             fibo(0)	fibo(1)

Modifiez le programme pour qu'il crée 2 fils. Le premier calculera fibo(n-2), le deuxième fibo(n-1). Le père récupérera les résultats et les additionnera. La communication sera assurée par des tubes.

Exercice 4

Le but est de mettre en oeuvre le cribble d'Ératosthène à l'aide d'une chaîne de processus reliés entre eux par des pipes.

  • un premier processus P crée un fils avec qui il est relié par un tube, et qui génére l'ensemble des nombres entre 2 et N (passé à la ligne de commande.)
  • Lorsqu'un nombre n'a pas été cribblé par les différents filtres, et arrive jusqu'à P, il est premier, et P crée un nouveau filtre.
┌────────┐
│   P    │
└────────┘

┌────────┐     ──────     ┌────────┐
│seq 2 N ├───►()    ()───►│   P    │
└────────┘     ──────     └────────┘

┌────────┐     ──────     ┌────────┐     ──────     ┌────────┐
│seq 2 N ├───►()    ()───►│   F2   ├───►()    ()───►│   P    │
└────────┘     ──────     └────────┘     ──────     └────────┘

┌────────┐     ──────     ┌────────┐     ──────     ┌────────┐     ──────     ┌────────┐
│seq 2 N ├───►()    ()───►│   F2   ├───►()    ()───►│   F3   ├───►()    ()───►│   P    │
└────────┘     ──────     └────────┘     ──────     └────────┘     ──────     └────────┘

┌────────┐     ──────     ┌────────┐     ──────     ┌────────┐     ──────     ┌────────┐     ──────     ┌────────┐
│seq 2 N ├───►()    ()───►│   F2   ├───►()    ()───►│   F3   ├───►()    ()───►│   F5   ├───►()    ()───►│   P    │
└────────┘     ──────     └────────┘     ──────     └────────┘     ──────     └────────┘     ──────     └────────┘

Écrire un programme correspondant à ce schéma.

TP 6 : Threads

Exercice 1

  1. Est-ce que lexécution de ce programme est correcte? Vous pouvez vous en assurer en lexécutant plusieurs fois.

Lexécution de ce programme nest pas correcte car quand nous exécutons le programme on retrouve plusieurs des threads qui affichent la même valeur de i.

  1. Si vous pensez (et avez constaté) que ce nest pas le cas, expliquez pourquoi.

Car il y a une variable i qui est partagée entre les threads et qui est modifié par le thread principal en même temps que les autres threads lisent la variable i.

  1. Modifiez le code pour quil donne le résultat attendu.

Exercice 2

Exercice 3

On veut écrire un programme calculant la somme des entiers de 1 à N à laide de M threads. Chaque thread calculera la somme dun sous-ensemble de ces entiers et la somme globale sera obtenue en calculant la somme des résultats intermédiaires de chaque thread.

Les entiers sont répartis uniformément entre les threads comme suit (exemple avec 3 threads) :

  • Thread 1 : 1, 4, 7, ...
  • Thread 2 : 2, 5, 8, ...
  • Thread 3 : 3, 6, 9, ...

Le programme doit lancer M threads, attendre quils se terminent, faire la somme des résultats intermédiaires et afficher le résultat. Les valeurs N et M seront passées en ligne de commande.

Il est important que le programme respecte les points suivants :

  • Limplémentation ne doit utiliser aucune variable globale.
  • Le travail à effectuer pour chaque thread créé doit être aussi équitable que possible, quelles que soient les valeurs N et M choisies par - lutilisateur (ex : N=20, M=8).
  • Évitez dutiliser un tableau pour contenir les valeurs à additionner.
  • Réaliser un test de validation automatiquement du résultat obtenu (vous devez connaître le résultat !).

Comparez le temps d'éxecution en fonction du nombre de threads.