Skip to content

MOOC NSI - fondamentaux.

Transcription de la vidéo

4.2.3.1 : Pourquoi les threads ?

[00:00:01]

Nous allons commencer à nous intéresser aux threads, appelée encore processus légers. Nous allons voir maintenant quelles sont les motivations qui ont amené à introduire la notion de threads en plus des processus que nous avons vu précédemment,.Les processus que nous avons vus précédemment sont en effet des processus lourds. Pourquoi ?

Puisqu'un processus a besoin de beaucoup de ressources système. Typiquement, il a besoin d'une zone mémoire à lui et il est géré par le système à l'aide d'une structure de données qui contient toutes les informations le concernant.

En plus, toutes les opérations de gestion de processus, c'est à dire création de processus, ordonnancement de processus, changement d'état deprocessus, terminaison de processus sont des opérations lentes, c'est à dire qu'elles ralentissent le fonctionnement global du système.

Par contre, les processus ont une caractéristique positive qui est l'isolation. Nous avons vu que grâce à l'isolation, le système d'exploitation garantit que les processus ne peuvent pas corrompre l'exécution. Par contre, à cause de l'isolation, les processus ont du mal à communiquer et donc à se coordonner. Or, nous avons besoin d'activités concurrentes, parallèles, qui peuvent se coordonner pour faire une tâche en commun. Dans la suite, nous allons voir trois exemples de fonctionnement où les processus sont difficiles à utiliser. Regardons un système d'exploitation. Vous savez que le système d'exploitation doit s'occuper de tout ce qui se passe sur la machine. et typiquement, doit réagir sur les événements qui arrivent, sur le réseau, sur le clavier, etc. Si on prend un système d'exploitation où tout est fait en séquentiel, il va falloir prévoir une boucle de ce type.

[00:01:58]

Typiquement, d'abord, on vérifie s'il y a quelque chose sur le réseau qui doit être traité. Ensuite, on vérifie s'il y a quelque chose qui vient du clavier. Ensuite, on regarde s'il faut faire quelque chose sur le disque. Ensuite, on regarde s'il faut lancer un processus, etc. Il est clair que là, on va se poser (la question) à quelle fréquence on va faire tourner cette boucle et dans quel ordre on va faire les vérifications. Il est clair que ce fonctionnement là n'est pas très efficace et ce qui est sûr, c'est qu'aucun système d'exploitation moderne ne marche de cette manière là. Ce que nous avons dans les systèmes modernes, c'est typiquement le code du système d'exploitation où nous avons des ressources en commun, des structures de gestion communes et après, nous avons des exécutions indépendantes : donc une activité qui va s'occuper du clavier, une activité qui va s'occuper du réseau, une troisième activité qui va s'occuper du disque, etc. Mais on est bien d'accord que ces trois activités vont générer des interruptions qui devraient se retrouver au même endroit de gestion au niveau du système d'exploitation, donc vont partager le même traitement d'interruptions.

Regardons maintenant un deuxième exemple, qui est un exemple de serveur de fichiers où un client demande un fichier, un serveur et le serveur lui envoie. Donc la requête de traitement de client dans la plupart des cas prend 15 millisecondes, mais une fois sur trois, le serveur a besoin d'aller chercher des informations supplémentaires sur disque

[00:03:40]

et ceci coûte 75 millisecondes de plus. Alors, si on fait le traitement des requêtes en séquentiel, on va voir première requête verte, deuxième requête verte, donc courte et troisième requête verte plus rose puisqu'on a besoin de temps supplémentaire d'accès disque. Ensuite, donc, on recommence : deux requêtes courtes, troisième requête longue. Avec ce fonctionnement là, on arrive à un débit de 25 requêtes/seconde. Si on sait faire des choses en parallèle, c'est-à-dire qu'on sait exécuter plusieurs traitements de requêtes, mais on sait répondre aux clients et en même temps aller chercher sur disque. Dans ce cas là, quand on commence à traiter la troisième requête, on va commencer aussi l'accès au disque et pendant que l'accès au disque est traité, on peut continuer avec le traitement des requêtes qui suivent. Dans ce cas là, oùu c'est le cas avec recouvrement, puisque la partie verte et la partie rose peuvent s'exécuter en parallèle, nous arrivons à un débit de 33,3 requêtes par seconde, c'est-à-dire qu'on a augmenté nos performances de plus de 30 %.

Troisième dernier exemple, exemple de serveur Web. Alors le client envoie une requête, le serveur reçoit la requête et puis il crée un processus pour traiter la requête et envoie la réponse. Donc, là, le serveur traite en séquentiel et en plus, paye le coût de créer le processus à chaque fois. On peut faire un petit peu mieux, on va se dire qu'on va créer plusieurs processus et on va les créer au début pour ne pas payer le prix de création à chaque requête.

[00:05:37]

Et quand une requête arrive, il va falloir choisir un processus qui traite la requête et qui envoie la réponse. C'est mieux en termes de performance, mais le serveur Web va toujours payer le coût de changement de contexte entre les processus. C'est pour cela qu’on arrive à la solution avec theads, où le fonctionnement est identique, mais les threads peuvent faire marcher le serveur Web plus rapidement puisque le changement de contexte entre threads est une opération beaucoup plus légère.

Dans ces trois exemples, ce que nous avons vu, c'est que nous avons besoin d'activités concurrentes, qui s'exécutent donc en parallèle, qui sont indépendantes en termes d'exécution, mais qui partagent des ressources. Elles ont besoin d'exécuter le même code, que ce soit le code de traitement de requêtes ou alors le code d'accès aux interruptions. Il faut qu'elles accèdent aux mêmes données, avoir les mêmes droits et éventuellement, partager des ressources. Ce qui, avec les processus, est difficile à mettre en œuvre. C'est pour cela qu’ont été introduits les threads. Les threads sont donc des flots d'exécution indépendants, appelés processus légers. Ils sont utilisés de manière importante dans les systèmes d'exploitation contemporains pour les besoins applicatifs et surtout pour pouvoir exploiter efficacement les nouvelles architectures matérielles où nous parlons de multi-processus multicœurs et donc pour exploiter ces unités de calcul efficacement il faut être capable d'exécuter plusieurs activités à la fois.

Comment on va utiliser les threads exactement? Nous allons le voir dans les séquences à venir.