Reword and syntax corrections

This commit is contained in:
Yorick Barbanneau 2022-01-07 00:55:12 +01:00
parent b95fe8380b
commit 5c682b618a

View file

@ -42,17 +42,17 @@ void exit_sc ()
``` ```
Nous avons donc besoin d'une solution non seulement valable pour un nombre Nous avons donc besoin d'une solution non seulement valable pour un nombre
indéfinis de fils d'exécutions, mais aussi plus efficace. indéfini de fils d'exécutions, mais aussi plus efficace.
## Une solution matérielle ## Une solution matérielle
Vu du processeur, une opération atomique ne peut être interompue par une autre. Vu du processeur, une opération atomique ne peut être interompue par une autre.
Les processeurs modernes en comportent un certain nombres. La solution viens Les processeurs modernes en comportent un certain nombre. La solution vient
donc des fabricant de processeurs. donc des fabricant de processeurs.
Pour forcer l'exclusion mutuelle, nous en avons besoin d'une seule: Pour forcer l'exclusion mutuelle, nous en avons besoin d'une seule:
`Test_and_Set`. C'est donc une instruction matérielle, voici une pseudo `Test_and_Set`. C'est donc une instruction matérielle, voici une pseudo
implémentation en C: implémentation en C :
```c ```c
int test_and_set (int *verrou){ int test_and_set (int *verrou){
@ -104,12 +104,13 @@ threads en attente. Car seul le noyau peut endormir les processus.
## Les sémaphores ## Les sémaphores
On en a déjà parlé [en lpro]({{< ref"../../progsys/8_IPC">}} "Les IPC"). Ce sont On en a déjà parlé [en lpro]({{<ref"../../progsys/8_IPC">}} "Les IPC"). Ce sont
des outils de haut-niveau, implémentés dans le noyau. Il se compose d'une des outils de haut-niveau, implémentés dans le noyau. Il se compose d'une
structures contenant un entier positif et une liste de processus en attente et structures contenant un entier positif, d'une liste de processus en attente et
de deux méthodes `P()` et `V()`. Il ont été inventés en 1962 par E. Dijsktra. de deux méthodes `P()` et `V()`. Il ont été inventés en 1962 par E. Dijsktra.
Les méthodes permettent : Les méthodes permettent :
* `P()`: attendre un jeton, le prendre lorqu'il devient disponible et continuer * `P()`: attendre un jeton, le prendre lorqu'il devient disponible et continuer
son exécution. son exécution.
* `V()`: remettre un jeton * `V()`: remettre un jeton
@ -146,7 +147,7 @@ void barrier (int i)
count[i] = 0; count[i] = 0;
V(mutex[i]); V(mutex[i]);
// point // point 2
for (int k=0; k < N-1; k++) for (int k=0; k < N-1; k++)
V(wait[i]); V(wait[i]);
} }
@ -154,6 +155,7 @@ void barrier (int i)
``` ```
Explication de code : Explication de code :
* **point 1**: Utiliser des tableaux de 2 éléments permet de réutiliser notre * **point 1**: Utiliser des tableaux de 2 éléments permet de réutiliser notre
fonction `barrier()` pour fixer plusieurs rendez-vous. Il suffit alors fonction `barrier()` pour fixer plusieurs rendez-vous. Il suffit alors
d'apeller à tous de rôle `barrier(0);` et `barrier(1);`. Sans ça un d'apeller à tous de rôle `barrier(0);` et `barrier(1);`. Sans ça un
@ -178,24 +180,24 @@ Un producteur appelle la fonction `put(element)` et un consommateurs
```c ```c
#define MAX 8 #define MAX 8
semaphore cons(0), prod(MAX) semaphore conso(0), prod(MAX)
// Pour le consommateur // Pour le consommateur
P(cons); P(conso);
elemet = get(); elemet = get();
V(prod); V(prod);
// Pour le producteur // Pour le producteur
P(prod); P(prod);
put(element); put(element);
V(cons); V(conso);
``` ```
Le fonctionnement est ici assez simple : Le fonctionnement est ici assez simple :
* **Pour le consomateur**: * **Pour le consomateur**:
1. il prend un jeton sur le sémaphore `cons` s'il est disponible (ou attends 1. il prend un jeton sur le sémaphore `conso` s'il est disponible (ou
qu'il le soit) attend qu'il le soit)
2. consomme l'élement 2. consomme l'élement
3. on relache celui sur `prod`. Cette dernière action permet de relancer 3. on relache celui sur `prod`. Cette dernière action permet de relancer
la production si la file était pleine (`prod` en attente). la production si la file était pleine (`prod` en attente).
@ -204,8 +206,8 @@ Le fonctionnement est ici assez simple :
action permet d'arrêter la production s'il n'y a plus de jeton action permet d'arrêter la production s'il n'y a plus de jeton
disponible. disponible.
2. On produit ensuite l'élément 2. On produit ensuite l'élément
3. puis on relache le sémaphore `cons`. On réveille ansi notre consommateur 3. puis on relache le sémaphore `conso`. On réveille ansi notre
s'il dormait en attendant la disponibilité d'un élement consommateur s'il dormait en attendant la disponibilité d'un élement
#### Multiple producteurs et consomateur #### Multiple producteurs et consomateur
@ -213,15 +215,15 @@ Dans la vraie vie, il y souvent plusieurs consomateurs / producteurs. Le
problème devient alors plus complexe... problème devient alors plus complexe...
Le code ressemble à celui ci-dessus, saut qu'il faut faire attention à ce qu'il Le code ressemble à celui ci-dessus, saut qu'il faut faire attention à ce qu'il
y ai un seul consmateir à la fois sur `get()` et un seul producteur sur y ai un seul consomateur à la fois sur `get()` et un seul producteur sur
`put(element)`. nous allons donc rajouter deux *"mutex"* : `put(element)`. nous allons donc rajouter deux *"mutex"* :
```c {linenos=table,hl_lines=[6,8,13,15]} ```c {linenos=table,hl_lines=[6,8,13,15]}
#define MAX 8 #define MAX 8
semaphore cons(0), prod(MAX), mutex_c(1), mutex_p(1); semaphore conso(0), prod(MAX), mutex_c(1), mutex_p(1);
// Pour le consomateir // Pour le consommateur
P(cons) P(conso)
P(mutex_v); P(mutex_v);
element = get(); element = get();
V(mutex_v); V(mutex_v);
@ -232,7 +234,7 @@ P(prod);
P(mutex_c); P(mutex_c);
put(element); put(element);
V(mutex_p); V(mutex_p);
V(cons) V(conso)
``` ```
### Problème des lecteurs rédacteurs ### Problème des lecteurs rédacteurs
@ -273,16 +275,18 @@ if(--nbr == 0) // last to leave
V(write_token); V(write_token);
V(mutex_r); V(mutex_r);
``` ```
Pour les lecteur, il faut envoyer **un éclaireur** afin de savoir si un lecteur
Pour les lecteurs, il faut envoyer **un éclaireur** afin de savoir si un lecteur
est actif. Le problème est similaire à celui des producteur consommateurs sauf est actif. Le problème est similaire à celui des producteur consommateurs sauf
qu'il faut savoir si notre lecteur est le premier *(ligne 12)* qu'il faut savoir si notre lecteur est le premier *(ligne 12)*
De plus. afin que notre algorithme ne privilegie pas les lecteurs au De plus, afin que notre algorithme ne privilegie pas les lecteurs au
détriment des rédacteur; ils peuvent même ne jamais rendre la main aux détriment des rédacteur; ils pourraient même ne jamais rendre la main aux
rédacteurs. Pour pallier au problème, nous devons mettre en place une **salle rédacteurs, nous devons mettre en place une **salle d'attente** *(ligne 8)*.
d'attente** *(ligne 8)*.
```c {linenos=table,hl_lines=[8,12]} Voici le code pour les rédacteurs:
```c {linenos=table}
P(wait_room); P(wait_room);
P(write_token); P(write_token);
V(wait_room); V(wait_room);
@ -296,7 +300,7 @@ Ce code est plutôt clair et ne comporte rien de particulier.
Les moniteurs sont des primitives de synchronisation initialement proposées dans Les moniteurs sont des primitives de synchronisation initialement proposées dans
les langages objet. Il est utilisé actuellemt dans des langages tel que ADA ou les langages objet. Il est utilisé actuellemt dans des langages tel que ADA ou
Java et implemente au sein de systèmes d'exploitation. Java et implementé au sein de systèmes d'exploitation.
Le moniteur se positionne sur une classe et les mutexes sur ses methodes et sont Le moniteur se positionne sur une classe et les mutexes sur ses methodes et sont
basés sur des variables condition. elle sont forcement privée et inaccessible à basés sur des variables condition. elle sont forcement privée et inaccessible à
@ -317,7 +321,7 @@ public method g() {
} }
``` ```
Il sont différent des *sémaphores*: il n'y a pas de jeton à prendre. Leur Il sont différents des *sémaphores*, il n'y a pas de jeton à prendre. Leur
implémentation dans les systèmes d'exploitation est différente, elle se fait par implémentation dans les systèmes d'exploitation est différente, elle se fait par
les les types `mutex_t` et `cond_t`: les les types `mutex_t` et `cond_t`:
@ -400,9 +404,10 @@ tout comme les barrières, le code est ici bien plus simple. Et bien entendu il
n'y a pas d'attente active... n'y a pas d'attente active...
Dans les codes ci-dessous, il est préféfable d'utiliser `while (nbe ...)` plutôt Dans les codes ci-dessous, il est préféfable d'utiliser `while (nbe ...)` plutôt
qu'un `if (nbe ...)`. (Mais je ne sais plus pourquoi...) qu'un `if (nbe ...)`. Si le processus se reveille, il faut s'arrurer que les
autres n'on pas déjà pris toutes les places disponibles.
Voici les variables nécessaires aux producteurs et au consomate Voici les variables nécessaires aux producteurs et au consommateurs.
```c ```c
#define MAX 8 #define MAX 8
@ -538,7 +543,7 @@ rwl_writeunlock(mylock);
## conclusion ## conclusion
Les sémaphores et moniyeurs sont implémentés au niveau du système d'exploitation Les sémaphores et moniteurs sont implémentés au niveau du système d'exploitation
et utilient le matériel sous-jacent (`test_and_set`). Ces appels sont et utilient le matériel sous-jacent (`test_and_set`). Ces appels sont
**coûteux**, nécessitent des **changements de contexte**. Dans les systèmes **coûteux**, nécessitent des **changements de contexte**. Dans les systèmes
modernes, on leur préfèrera un **mix de primitive de synchronisation et de modernes, on leur préfèrera un **mix de primitive de synchronisation et de
@ -548,11 +553,11 @@ pendant quelques cycles et se bloquera si elle n'est pas disponible.
Les moniteurs de Hoare sont en général préférés par les programmeurs cas comme Les moniteurs de Hoare sont en général préférés par les programmeurs cas comme
on l'a vu, ils sont plus simple à implémenter. on l'a vu, ils sont plus simple à implémenter.
Il eest intéressant aussi de parler des **FUTEX**, apparus en 2003 sur Linux et Il est intéressant aussi de parler des **FUTEX**, apparus en 2003 sur Linux et
plus tard sous Windows 8 (sous l'appelation `wait_on_address` et brevete en plus tard sous Windows 8 (sous l'appelation `wait_on_address` et breveté en
2013). 2013).
Ils utilisent des opétations atomiques sur des variables entières de 32bits *en Ils utilisent des opérations atomiques sur des variables entières de 32bits *en
espace utilisateur* et deux operation bloquante si nécessaires: espace utilisateur* et deux operation bloquante si nécessaires:
```c ```c