Changes between Version 76 and Version 77 of AS6-TME-B5


Ignore:
Timestamp:
Mar 17, 2024, 12:27:17 PM (15 months ago)
Author:
franck
Comment:

--

Legend:

Unmodified
Added
Removed
Modified
  • AS6-TME-B5

    v76 v77  
    246246'''
    247247}}}
    248 1. La structure `thread_s` rassemble les propriétés du thread, sa pile et le tableau de sauvegarde de son contexte. Cette structure est, dans l'état actuel du code` entièrement dans dans le segment des données globales de l'application. Pouvez-vous justifier cette situation et en discuter ?
     2481. La structure `thread_s` rassemble les propriétés du thread, sa pile et le tableau de sauvegarde de son contexte. Cette structure est, dans l'état actuel du code entièrement dans dans le segment des données globales de l'application. Pouvez-vous justifier cette situation et en discuter ?
    249249{{{#!protected ------------------------------------------------------------------
    250250'''
     
    276276'''
    277277}}}
    278 1. La fonction `sched_switch()` appelle d'abord l'électeur de thread qui choisit le thread entrant (qui gagne le processeur), puis `sched_switch()` sauve le contexte du thread sortant (qui perd le processeur) et charge le contexte du thread entrant, enfin `sched_switch()` change l'état du thread entrant à `RUNNING`. `sched_switch()` est appelée par `thread_yield()`. Pouvez-vous expliquer pourquoi avoir créé `sched_switch()` ? Ce n'est pas évident au premier abord, mais il y a une raison.
    279 {{{#!c
     2781. L'ordonnanceur est codé dans la fonction `sched_switch()`. Il est appelé par `thread_yield()` et par `thread_exit()` (et par d'autres fonctions que nous verrons plus tard).\\La fonction `sched_switch()` appelle d'abord l'électeur de thread qui choisit le thread entrant (qui gagne le processeur), puis `sched_switch()` sauve le contexte du thread sortant (qui perd le processeur) et charge le contexte du thread entrant, enfin `sched_switch()` change l'état du thread entrant à `RUNNING`.\\Est-ce que `sched_switch()` sait pourquoi un thread demande à perdre le processeur ?
     279{{{#!c
     280int thread_yield (void) {
     281  thread_tab[thread_current_idx]->state = TH_STATE_READY;  // état futur du thread sortant
     282  sched_switch ();                                         // changement de threads (ou pas)
     283  return 0;
     284}
    280285void sched_switch (void) { //
    281286  int th_curr = thread_current_idx;                        // n° du thread courant dans thread_tab
     
    289294  thread_tab[thread_current_idx]->state= TH_STATE_RUNNING; // the thread choisi est dans l'état
    290295}
    291 int thread_yield (void) {
    292   thread_tab[thread_current_idx]->state = TH_STATE_READY;  // état futur du thread sortant
    293   sched_switch ();                                         // changement de threads (ou pas)
    294   return 0;
    295 }}}
    296 {{{#!protected ------------------------------------------------------------------
    297 '''
    298  * Si vous avez trouvé, vraiment bravo !
    299  * Un principe de fonctionnement de l'ordonnanceur, c'est que l'ordonnanceur ignore la raison pour laquelle un thread perd le processeur.
    300  * Son travail, c'est d'élire un nouveau thread entrant, sauver le contexte du thread sortant et charger le contexte du thread entrant. Il change également l'état du thread entrant à `RUNNING` parce qu'il sait que c'est le bon état (il vient de charger un contexte et donc le thread entrant est nécessairement le ''`RUNNING` thread'').
    301  * Actuellement, un thread a deux manières de perdre le processeur : `thread_yield()` et `thread_exit()`:
     296}}}
     297{{{#!protected ------------------------------------------------------------------
     298'''
     299 * Non, l'ordonnanceur `sched_switch()` ignore pourquoi le thread_courant demande à perdre le processeur. 
     300 * Le travail de l'ordonnanceur, c'est d'élire un nouveau thread entrant, sauver le contexte du thread sortant et charger le contexte du thread entrant, puis de changer l'état du thread entrant à `RUNNING` parce qu'il sait que c'est toujours le bon état (il vient de charger un contexte et donc le thread entrant est nécessairement le ''`RUNNING` thread'').
     301 * Actuellement, un thread n'a que deux manières de perdre le processeur : `thread_yield()` et `thread_exit()`:
    302302{{{#!c
    303303int thread_yield (void) {
     
    311311}
    312312}}} 
    313  * Comme vous pouvez le voir, dans ces fonctions, on commence par changer l'état du thread et après on appelle `sched_switch()`.
    314  * Pour le moment, c'est un simple changement d'état avant l'appel à `sched_switch()`, mais plus tard, il y aura d'autres opérations, pour la gestion des listes d'attente des ressources partagées ou la gestion des terminaisons de threads dont d'autres attendent la terminaison (avec `thread_join`).
     313 * Comme vous pouvez le voir dans ces fonctions, on commence par changer l'état du thread sortant et après on appelle `sched_switch()`.
     314 * Pour le moment, c'est un simple changement d'état du thread sortant avant l'appel à `sched_switch()`, mais plus tard, il y aura d'autres opérations à faire entre ce changement d'état du thread sortant et l'appel de `sched_switch()`, pour la gestion des listes d'attente des ressources partagées ou la gestion des terminaisons de threads dont d'autres threads attendent la terminaison (avec `thread_join`).
     315 * C'est pour cette raison que `sched_switch()` ne peut pas se charger du changement d'état du thread sortant, même s'il recevait cet état en argument.
    315316'''
    316317}}}
     
    403404{{{#!protected ------------------------------------------------------------------
    404405'''
    405  * Si les appels système ne sont plus interruptibles, ils ne doivent plus être bloquants !
    406 '''
    407 }}}
    408 1. Que doit-faire le noyau si un thread lui demande une ressource qu'il n'a pas ? Il ne peut pas attendre la ressource, alors il a deux possibilités, les voyez-vous ? Mettez-vous à sa place si vous devez gérer des ressources, par exemple des places dans un restaurant, que vous avez des clients qui se présentent et que toutes les places sont occupées. Que faites-vous ?
     406 * Si les appels système ne sont plus interruptibles, ils ne doivent plus être bloquants pour l'application !\\Cela signifie que s'il ne peuvent pas rendre immédiatement le service demandé, ils doivent céder le processeur avec `thread_yield()`.
     407'''
     408}}}
     4091. Que doit-faire le noyau si un thread A lui demande une ressource que le noyau n'a pas ?\\Le thread A ne doit pas attendre activement la ressource par scrutation parce que c'est du gâchis de temps CPU, alors le noyau a deux possibilités, les voyez-vous ?\\Mettez-vous à la place du noyau si vous devez gérer des ressources, par exemple des places dans un restaurant, que vous avez des clients qui se présentent et que toutes les places sont occupées. Que faites-vous ?
    409410{{{#!protected ------------------------------------------------------------------
    410411'''
    411412 * Deux possibilités :
    412    1. Soit le noyau abandonne le service et rend une erreur au thread pour l'informer que le service ne peut pas être rendu, et donc que le thread doit retenter sa chance plus tard ou faire autre chose. Pour l'analogie, vous dites à votre client de partir et de, s'il veut, revenir plus tard ou pas.
    413    2. Soit le noyau demande un changement de thread avec `thread_yield()` pour faire quelque chose d'utile pour un autre thread. Pour l'analogie, vous dites à votre client d'attendre et vous allez faire autre chose. Le client attend et tente de rentrer dès qu'un autre client sort du restaurant. Notez que dans cette analogie, il n'y a pas de file d'attente, le dernier client arrivé sera peut-être le premier servi.
     413   1. Soit le noyau informe le thread A que le service ne peut être rendu en retournant un code d'erreur pour l'informer  et donc que le thread A doit retenter sa chance plus tard ou faire autre chose. Pour l'analogie, vous dites à votre client de partir et de revenir plus tard ou pas.
     414   2. Soit le noyau demande un changement de thread avec `thread_yield()` pour le thread A qui demande la ressource, ainsi le noyau peux faire quelque chose d'utile pour un autre thread. Le thread A reste dans la dans le noya Pour l'analogie, vous dites à votre client de se mettre dans une file d'attente et vous allez faire autre chose. Le client attend et tente de rentrer dès qu'un autre client sort du restaurant. Notez que dans cette analogie, il n'y a pas de file d'attente, le dernier client arrivé sera peut-être le premier servi.
    414415 * Dans la version actuelle du code, le thread qui attend la ressource reste dans l'état READY et donc il sera élu par l'ordonnanceur quand son tour viendra pour tester à nouveau la ressource et la prendre si elle est disponible, sinon il subit à nouveau un `thread_yield()`.
    415416 * Ce comportement sera modifié en introduisant un état `WAIT` pour les threads afin de l'ordonnanceur ne donne pas le processeur à un thread dont la ressource attendue n'est pas disponible.