Synchronisation : exercices
Des exercices complémentaires se trouvent sur cette page.
Liste des problèmes
Énoncé: Création de processus
Combien de processus exécuteront le code
suivant ?
int main () { int i; for (i = 0; i < 4; i++) { fork (); } exit (0); }
Énoncé: Ressource non bloquante
Plusieurs processus souhaitent accéder à une
ressource partagée uniquement si celle-ci est disponible, sans
bloquer (potentiellement longtemps) sur un sémaphore si elle est
occupée. Comment faire ?
Énoncé: Compteur protégé
On souhaite partager un compteur N entre
différents processus, qui pourront l’incrémenter et le décrémenter.
Quel est le problème si les processus le manipulent directement
?
Comment le protéger ?
Les processus utilisent ce compteur pour
compter le nombre de processus en attente sur une ressource
protégée par un sémaphore S. Un processus préfère échouer s’il y a
déjà 10 processus en attente, plutôt que d’être bloqué. Comment
faire ?
Solution: Création de processus
Combien de processus exécuteront le code
suivant ?
int main () { int i; for (i = 0; i < 4; i++) { fork (); } exit (0); }
Le nombre de processus double à chaque étape.
Lorsqu’un processus est cloné, i hérite de la même valeur, et le
père et le fils se retrouvent au même point.
- Au début: 1 processus
- Quand i vaut 0, 1 nouveau processus, total: 2
- Quand i vaut 1, 2 nouveaux processus, total: 4
- Quand i vaut 2, 4 nouveaux processus, total: 8
- Quand i vaut 3, 8 nouveaux processus, total: 16
Solution: Ressource non bloquante
Plusieurs processus souhaitent accéder à une
ressource partagée uniquement si celle-ci est disponible, sans
bloquer (potentiellement longtemps) sur un sémaphore si elle est
occupée. Comment faire ?
On doit utiliser un sémaphore, mais sur une
section critique la plus courte possible. Pour cela, on utilise un
sémaphore S initialisé avec
Init (S, 1);et une variable indiquant si la ressource est disponible initialisée avec
libre = 1;Le code pour faire un traitement si la ressource est disponible est maintenant:
P (S); if (libre == 1) { libre = 0; /* La ressource est maintenant prise */ V (S); ... /* Traitement potentiellement long */ libre = 1; /* La ressource est maintenant disponible */ } else { V (S); }
Solution: Compteur protégé
On souhaite partager un compteur N entre
différents processus, qui pourront l’incrémenter et le décrémenter.
Quel est le problème si les processus le manipulent directement
?
Si le code est
N = N + 1alors la loi de Murphy (dite aussi « loi de l’emmerdement maximal ») fera qu’un des processus sera interrompu après le calcul de N+1 mais avant l’écriture de la nouvelle valeur. Lorsqu’il reprendra la main, il écrira une valeur obsolète.
Comment le protéger ?
Il suffit de créer un sémaphore X initialisé par
Init (X, 1)et de protéger par une section critique tous les accès au compteur:
P (X); N = N + 1; V (X);
Les processus utilisent ce compteur pour
compter le nombre de processus en attente sur une ressource
protégée par un sémaphore S. Un processus préfère échouer s’il y a
déjà 10 processus en attente, plutôt que d’être bloqué. Comment
faire ?
P (X); if (N == 10) { /* Il y a déjà 10 processus en attente, échouer */ V (X); return -1; } N = N + 1; V (X); /* Obtention de la ressource protégée */ P (S); /* Décrémentation du nombre de processus en attente */ P (X); N = N - 1; V (X); /* Utilisation de la ressource */ ... /* Libération de la ressource et sortie avec succès */ V (S); return 0;