Changes between Version 32 and Version 33 of AS6-TME-B7


Ignore:
Timestamp:
Apr 2, 2024, 6:17:56 PM (14 months ago)
Author:
franck
Comment:

--

Legend:

Unmodified
Added
Removed
Modified
  • AS6-TME-B7

    v32 v33  
    6060- **Le mécanisme de base est le verrou**
    6161  - Les mécanismes de synchronisation s'appuient un mécanisme élémentaire, le verrou binaire, un objet à deux états : `busy`/`free`. `busy` signifie que le verrou est fermé que l'on ne peut pas avancer au delà dans le programme. `free`signifie que le verrou est ouvert et que l'on peut passer.
    62   - Il y a deux opérations de base: `lock`/`unlock`. L'opération `lock` signifie le souhait de fermer le verrou, donc de le passer à busy, ce qui n'est possible que s'il est `free`. `lock` est donc bloquant si verrou est déjà busy et c'est une attente active (une boucle jusqu'à réussite). `unlock` signifie ouvrir le verrou. Ce n'est pas bloquant.
     62  - Il y a deux opérations de base: `lock`/`unlock`. L'opération `lock` signifie le souhait de fermer le verrou (pour interdire aux autres de passer, on dit aussi prendre le verrou), donc de passer l'état à busy, ce qui n'est possible que s'il est `free`. `lock` est donc bloquant si verrou est déjà busy et c'est une attente active (une boucle jusqu'à réussite). `unlock` signifie ouvrir le verrou ou lâcher le verrou. Ce n'est pas bloquant.
    6363  - Le mécanisme de base des verrous utilise la possibilité de réaliser une séquence atomique d'instructions read-modify-write qui permet de lire l'état du verrou, de le tester et de le modifier s'il est libre avec la garantie que si on y parvient on est le seul.
    6464  - Il existe plusieurs solutions matérielles pour implémenter les verrous avec des instructions permettant de créer des séquences atomiques d'instructions : mémoire de verrous, instructions CAS, TAS ou couples d'instruction LL/SC.
     
    7474- **Les ressources partagées gèrent des listes d'attente de threads**
    7575  - Quand une ressource est partagée, il existe une API permettant de ''prendre'' la ressource (ici ''prendre'' est très général, le nom de la fonction dépend du type de ressource.
    76   - Si la ressource n'est pas disponible, le thread demandeur est mis en attente dans une liste d'attente de thread dans l'état `WAIT`. Cette liste est propre à la ressource. Il sort de la liste lorsque le propriétaire actuel rend la ressource et le choisit parmi tous ceux en train d'attendre. Il repasse à l'état `READY` donc éligible par l'ordonnanceur.
     76  - Si la ressource n'est pas disponible, le thread demandeur est mis en attente dans une liste d'attente de thread dans l'état `WAIT`. Cette liste est propre à chaque ressource.
     77  - Un thread sort de la liste d'attente lorsque le propriétaire actuel rend la ressource et le choisit parmi tous ceux en train d'attendre. Il repasse à l'état `READY` donc éligible par l'ordonnanceur.
    7778
    7879- **Les deux nouvelles fonctions de transition d'états pour les threads**
     
    8283  - Quand un thread veut prendre une ressource indisponible, il s'accroche à la liste d'attente de la la ressource et il appelle `thread_wait()`.
    8384  - Quand un thread libère une ressource et que celle-ci est attendue, le ''libérateur'' choisit un thread de la liste d'attente, il le décroche et il appelle `thread_notify()`.
     85  - Le choix du thread parmi tous ceux en attente est une opération d'ordonnancement, ici c'est l'ordre premier-arrivé-premier-servi.
    8486
    8587- **"''Race Condition''" ou "Condition de Compétition"**
     
    8991
    9092- **Le Mutex est un verrou avec liste d'attente utilisable par l'application**
    91   - l'API...
     93  - On peut utiliser des `spinlocks` en mode utilisateur, mais ce sont des attentes actives ce qui signifie qu'un thread peut passer tout son quantum de temps processeur à attendre.
     94  - Les mutex permettent d'éviter cette attente inutile en mettant explicitement les threads demandeur dans une liste d'attente, dans un état inéligible par l'ordonnanceur.
     95  - Les threads sortent de la liste d'attente dès que le mutex est libéré.
     96  - Les opérations de bases sont `lock`/`unlock` comme pour le `spinlock`.
     97  - Seul le thread ayant verrouillé `lock` un mutex a le droit de le déverrouiller `unlock`.
    9298
    9399- **`thread_join()` permet à un thread d'attendre le `thread_join()` d'un autre
    94   - Un thread rend un pointeur générique `void *` qui ne peut être récupérer que par un appel à la fonction `thread_join(thread_t th, void **retval)` avec comme arguments: le thread attendu `th` et un pointeur sur une variable pouvant contenir un pointeur générique `void *` (`void **retval`).
    95   - ...
     100  - Un thread rend un pointeur générique `void *` lors de sa terminaison. Ce pointeur `void *` ne peut être récupérer que par un appel à la fonction `thread_join(thread_t th, void **retval)` avec comme arguments: le thread attendu `th` et un pointeur sur une variable pouvant contenir un pointeur générique `void *` (`void **retval`).
     101  - `thread_join()` permet donc de se mettre en attente de la terminaison d'un thread.
     102  - `thread_join()` est une fonction bloquante pour le thread qui fait le join, sauf si le thread attendu est déjà terminé.
     103  - C'est `thread_join()` qui fait passer l'état du thread attendu de `ZOMBIE` à `DEAD`.
    96104
    97105- **Les codes d'erreur des appels systèmes sont dans la variable globale `errno`
    98106  - La variable `errno` est globale parce qu'elle est connue et utilisable par toutes les fonctions de l'application, mais chaque thread dispose de sa propre valeur.
    99107  - Les variables globales mais locales aux threads font partie du ''thread local storage''
    100   - ...
    101  
    102 (pas fini)
     108  - Pour ko6, cette variable globale est placé en haut de chaque pile utilisateur, il y a donc autant de valeurs possibles de cette variable qu'il y a de threads.
     109  - On obtient l'adresse de la variable par un syscall.
    103110
    104111