Cours informatique les threads

Les threads

Actuellement, toutes les machines, qu’elles soient monoprocesseur ou multiprocesseur, per- mettent d’exécuter plus ou moins simultanément plusieurs programmes (on parle encore de tâches ou de processus). Sur les machines monoprocesseur, la simultanéité, lorsqu’elle se manifeste, n’est en fait qu’une illusion : à un instant donné, un seul programme utilise les res- sources de l’unité centrale ; mais l’environnement « passe la main » d’un programme à un autre à des intervalles de temps suffisamment courts pour donner l’impression de la simultanéité ; ou encore, l’environnement profite de l’attente d’un programme (entrée utilisateur, lecture ou écriture sur disque, attente de fin de transfert d’un fichier Web…) pour donner la main à un autre. indépendants. Le contrôle de l’exécution de ces différents threads (c’est-à-dire la façon dont la main passe de l’un à l’autre) se fera alors, au moins partiellement, au niveau du programme lui-même et ces threads pourront facilement communiquer entre eux et partager des données.. Puis nous verrons comment interrompre un thread depuis un autre thread, ce qui nous amènera à parler des threads démons. Nous apprendrons ensuite à coordonner les actions de plusieurs threads, d’une part en définissant des méthodes dites synchronisées, d’autre part en gérant des attentes faisant intervenir la notion de verrou sur un objet. Nous passerons alors en revue les différents états d’un thread. Enfin, nous verrons comment agir sur la priorité d’un thread.

A un instant donné, une seule méthode synchronisée peut donc accéder à un objet donné. Pour mettre en place une telle contrainte, on peut considérer que, pour chaque objet doté d’au moins une méthode synchronisée, l’environnement gère un « verrou » (ou une clé) unique per- mettant l’accès à l’objet. Le verrou est attribué à la méthode synchronisée appelée pour l’objet et il est restitué à la sortie de la méthode. Tant que le verrou n’est pas restitué, aucune autre méthode synchronisée ne peut le recevoir (bien sûr, les méthodes non synchronisées peuvent, quant à elles, accéder à tout moment à l’objet).Comme on peut s’y attendre, Java n’est pas en mesure de détecter ce genre de situation et c’est au programmeur qu’il incombe de gérer cette tâche. A simple titre indicatif, il existe une technique dite d’ordonnancement des ressources qui consiste à numéroter les verrous dans un certain ordre et à imposer aux threads de demander les verrous suivant cet ordre. On évite alors à coup sûr les situations d’interblocage.Dans l’exemple du paragraphe 4.2, les deux threads calc et aff n’étaient pas coordonnés ; on pouvait incrémenter plusieurs fois le nombre avant qu’il n’y ait affichage ou, encore, afficher plusieurs fois les mêmes informations. Ici, nous allons faire en sorte que, malgré leurs rythmes différents, les deux threads soient coordonnés, c’est-à-dire qu’on effectue alternative- ment une incrémentation et un calcul. Pour ce faire, nous utilisons les méthodes wait et notifyAll, ainsi qu’un indicateur booléen prêt permettant aux deux threads de communiquer entre eux.

Nous avons déjà vu comment un thread pouvait être mis en sommeil ou mis en attente du verrou d’un objet. Nous allons ici faire le point sur les différents « états » dans lesquels peut se trouver un thread et sur les actions qui le font passer d’un état à un autre. Au départ, on crée un objet thread. Tant que l’on ne fait rien, il n’a aucune chance d’être exécuté. L’appel de start rend le thread disponible pour l’exécution. Il est alors considéré comme prêt. L’environnement peut faire passer un thread de l’état prêt à l’état « en cours d’exécution ». On notera bien que cette transition ne peut pas être programmée explicitement. C’est le système qui décide (en utilisant éventuellement des requêtes formulées par le programme).Aucune garantie n’est fournie quant à la répartition équitable du temps d’exécution entre différents threads de même priorité. Comme nous l’avons déjà évoqué, suivant les environnements, on pourra avoir un partage de temps systématique entre ces threads ou, au contraire, voir un thread s’exécuter totalement avant qu’un autre n’obtienne la main. On notera que d’éventuels appels de yield ne changent rien à ce problème. En revanche, comme nous l’avons vu, des appels judicieux de sleep peuvent permettre d’aboutir à une relative indépen- dance de l’environnement. Au chapitre 1, nous avons sommairement indiqué ce qui distingue un programme à interface console d’un programme à interface graphique. Dans le premier cas, c’est le programme qui pilote l’utilisateur en le sollicitant au moment voulu pour qu’il fournisse des informations ; le dialogue se fait en mode texte et de façon séquentielle, dans une fenêtre nommée « console ». Dans le second cas, au contraire, l’utilisateur a l’impression de piloter le programme qui réa- git à des demandes qu’il exprime en sélectionnant des articles de menu, en cliquant sur des boutons, en remplissant des boîtes de dialogue… Malgré l’adjectif « graphique » utilisé dans l’expression « interface graphique », la principale caractéristique de ces programmes réside dans la notion de programmation événementielle.

 

Cours gratuitTélécharger le document complet

Télécharger aussi :

Laisser un commentaire

Votre adresse e-mail ne sera pas publiée. Les champs obligatoires sont indiqués avec *