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 |
| 278 | 1. 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 |
| 280 | int 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 | } |
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()`: |
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. |
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 | }}} |
| 409 | 1. 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 ? |
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. |