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;