Thread (informatique)

{{#ifeq:||Un article de Ziki, l'encyclopédie libre.|Une page de Ziki, l'encyclopédie libre.}}

Modèle:Langue du titre Modèle:Voir homonymes

Fichier:Multithreaded process.svg
Un processus avec deux Modèle:Langue.

Un Modèle:Langue ou fil (traduction normalisés par ISO/CEI 2382-7:2000<ref name="iso.org">Modèle:Lien web</ref> (autres appellations connues : processus léger, fil d'exécution, fil d'instruction, processus allégé, exétron, tâche, voire unité d'exécution<ref>Modèle:Ouvrage</ref> ou unité de traitement<ref>Modèle:Ouvrage</ref>,<ref>Programmation Linux en pratique, Arnold Robbins, CampusPress Référence, Modèle:ISBN, Modèle:P..</ref>Modèle:Refnec) est similaire à un processus car tous deux représentent l'exécution d'un ensemble d'instructions du langage machine d'un processeur.

Du point de vue de l'utilisateur, ces exécutions semblent se dérouler en parallèle. Toutefois, là où chaque processus possède sa propre mémoire virtuelle, les Modèle:Langue d'un même processus se partagent sa mémoire virtuelle. En revanche, tous les Modèle:Langue possèdent leur propre pile d'exécution.

Utilisation

Les Modèle:Langue sont classiquement utilisés avec l'interface graphique (Graphical user interface) d'un programme, pour des attentes asynchrones dans les télécommunications ou encore pour des programmes de calcul intensif (comme l'encodage d'une vidéo, les simulations mathématiques, etc.).

En effet, dans le cas d'une interface graphique, les interactions de l'utilisateur avec le processus, par l'intermédiaire des périphériques d'entrée, sont gérées par un Modèle:Langue, technique similaire à celle utilisée pour les attentes asynchrones, tandis que les calculs lourds (en termes de temps de calcul) sont gérés par un ou plusieurs autres Modèle:Langue. Cette technique de conception de logiciel est avantageuse dans ce cas, car l'utilisateur peut continuer d'interagir avec le programme même lorsque celui-ci est en train d'exécuter une tâche. Une application pratique se retrouve dans les traitements de texte où la correction orthographique est exécutée tout en permettant à l'utilisateur de continuer à entrer son texte. L'utilisation des Modèle:Langue permet donc de rendre l'utilisation d'une application plus fluide, car il n'y a plus de blocage durant les phases de traitements intenses.

Dans le cas d'un programme de calcul intensif, l'utilisation de plusieurs Modèle:Langue permet de paralléliser le traitement, ce qui, sur les machines multiprocesseur, permet de l'effectuer bien plus rapidement.

Modèle:Langue et multitâche

Deux processus sont totalement indépendants et isolés l'un de l'autre. Ils ne peuvent interagir qu'à travers une API fournie par le système, telle qu'IPC, tandis que les Modèle:Langue partagent une information sur l'état du processus, des zones de mémoires, ainsi que d'autres ressources. En fait, à part leur pile d’appel, des mécanismes comme le Thread Local Storage et quelques rares exceptions spécifiques à chaque implémentation, les Modèle:Langue partagent tout. Puisqu'il n'y a pas de changement de mémoire virtuelle, la commutation de contexte (Modèle:Lang) entre deux Modèle:Langue est moins coûteuse en temps que la commutation de contexte entre deux processus. On peut y voir un avantage de la programmation utilisant des Modèle:Langue multiples.

Avantages et inconvénients

Dans certains cas, les programmes utilisant des Modèle:Langue sont plus rapides que des programmes architecturés plus classiquement, en particulier sur les machines comportant plusieurs processeurs. Hormis le problème du coût de la commutation de contexte, le principal surcoût dû à l'utilisation de processus multiples provient de la communication entre processus séparés. En effet, le partage de ressources entre Modèle:Langue permet une communication plus efficace entre les différents Modèle:Langue d'un processus qu'entre deux processus distincts. Là où deux processus séparés doivent utiliser un mécanisme fourni par le système pour communiquer, les Modèle:Langue partagent une partie de l'état du processus, notamment sa mémoire. Dans le cas de données en lecture seule, il n'y a même pas besoin du moindre mécanisme de synchronisation pour que les Modèle:Langue utilisent les mêmes données.

La programmation utilisant des Modèle:Langue est toutefois plus rigoureuse que la programmation séquentielle, et l'accès à certaines ressources partagées doit être restreint par le programme lui-même, pour éviter que l'état d'un processus ne devienne temporairement incohérent, tandis qu'un autre Modèle:Langue va avoir besoin de consulter cette portion de l'état du processus. Il est donc obligatoire de mettre en place des mécanismes de synchronisation (à l'aide de sémaphores, par exemple), tout en conservant à l'esprit que l'utilisation de la synchronisation peut aboutir à des situations d'interblocage si elle est mal utilisée.

La complexité des programmes utilisant des Modèle:Langue est aussi nettement plus grande que celle des programmes déférant séquentiellement le travail à faire à plusieurs processus plus simples (la complexité est similaire dans le cas de plusieurs processus travaillant en parallèle). Cette complexité accrue, lorsqu'elle est mal gérée lors de la phase de conception ou de mise en œuvre d'un programme, peut conduire à de multiples problèmes tels que :

  • interblocages apparemment aléatoires :
    • si un algorithme est mal conçu et permet un interblocage, le changement de vitesse du processeur, par l'utilisation incomplète d'un quantum de temps alloué ou au contraire de la nécessité d'utiliser un quantum supplémentaire, peut provoquer la situation d'interblocage ;
    • de même, des périphériques plus ou moins rapides que ceux de la machine ayant servi à développer/tester le programme induisent des synchronisations temporellement différentes, et donc peuvent provoquer un interblocage non détecté auparavant ;
    • enfin, le changement de charge processeur de la machine (un programme lourd tournant en parallèle, par exemple) peut là aussi déclencher plus facilement des interblocages qui n'avaient pas été vus auparavant, avec l'illusion d'un phénomène aléatoire.
  • complexification inutile de certains algorithmes, qui ne bénéficient pas de la parallélisation du code mais qui sont pénalisés par des synchronisations d'accès aux ressources partagées :
    • sur-parallélisation du code alors qu'un traitement séquentiel serait plus adapté, la perte de temps liée à la commutation de contexte n'étant pas compensée par la parallélisation ;
    • Introduction de variables globales, forçant l'utilisation de synchronisation à outrance et donc des commutations de contexte inutiles.
  • sur-utilisation des mécanismes de synchronisation inadaptés là où ils ne sont pas nécessaires, induisant un surcoût de temps processeur inutile :

Support des Modèle:Langue

Systèmes d'exploitation

Les systèmes d'exploitation mettent généralement en œuvre les Modèle:Langue, souvent appelés Modèle:Langue système ou Modèle:Langue natifs (par opposition aux Modèle:Langue liés à un langage de programmation donné). Ils sont utilisés au travers d'une API propre au système d'exploitation, par exemple Windows API ou les Threads POSIX. En général, cette API n'est pas orientée objet, et peut être relativement complexe à bien mettre en œuvre car composée uniquement de fonctions primitives, ce qui demande souvent à avoir quelques notions sur le fonctionnement de l'ordonnanceur.

L'avantage des Modèle:Langue natifs est qu'ils permettent des performances maximales, car leur API permet de minimiser le temps passé dans le noyau et d'éliminer les couches logicielles inutiles. Leur principal inconvénient est, de par la nature primitive de l'API, une plus grande complexité de mise en œuvre.

Langages de programmation

Certains langages de programmation, tels que Smalltalk et certaines implémentations de Java<ref>{{#invoke:Langue|indicationDeLangue}} « Modèle:Langue » (éléments sur le support des Modèle:Langue sur le site officiel Sun)</ref>,<ref>{{#invoke:Langue|indicationDeLangue}} « Modèle:Langue » (guide d'utilisation des Modèle:Langue sous Java sur le site JavaWorld).</ref>,<ref>{{#invoke:Langue|indicationDeLangue}} « Modèle:Langue » (annonce sur le site officiel Modèle:Langue d'abandon des Modèle:Langue sur Linux).</ref>,<ref>{{#invoke:Langue|indicationDeLangue}} « Modèle:Langue » (documentation officielle Modèle:Langue sur le modèle de Modèle:Langue sur Solaris).</ref>, intègrent un support pour les Modèle:Langue implémentés dans l'espace utilisateur (Modèle:Lien), indépendamment des capacités du système d'exploitation hôte.

La plupart des langages (Java sur la plupart des systèmes d'exploitation, C# .NET, C++, Ruby…) utilisent des extensions du langage ou des bibliothèques pour utiliser directement les services de multithreading du système d'exploitation, mais de façon portable. Enfin, des langages comme Haskell utilisent un système hybride à mi-chemin entre les deux approches. À noter que, pour des raisons de performances en fonction des besoins, la plupart des langages permettent d'utiliser au choix des Modèle:Langue natifs ou des Modèle:Langue (notamment via l'utilisation de fibres). D'autres langages, comme Ada (langage), implémentent également un multitâche indépendant du système d'exploitation sans pour autant utiliser réellement le concept de Modèle:Langue.

Le C++, depuis la nouvelle norme du C++ nommée C++11, possède aussi une bibliothèque de gestion des Modèle:Langue (issue de Boost) : le modèle de classe est std::thread. Celui-ci est simple d'utilisation, et permet de bien créer et exécuter ses Modèle:Langue. Auparavant, chaque framework devait implémenter sa propre surcouche de gestion des Modèle:Langue, en général câblée directement sur les Modèle:Langue natifs du système.

Paradigmes de développement

Paradigmes de développement :

Réentrance

En programmation parallèle, le principe de base est d'assurer la réentrance des entités logicielles utilisées par les Modèle:Langue, soit par conception (fonctions pures), soit par synchronisation (notamment par l'utilisation d'un mutex encadrant l'appel à la fonction).

Programmation procédurale

En programmation procédurale, on utilise le plus souvent directement les Modèle:Langue natifs du système d'exploitation. Leur utilisation est alors directement dépendante de l'API du système, avec ses avantages et inconvénients. Notamment, les fonctions utilisées par les Modèle:Langue doivent être réentrantes ou protégées par mutex.

Programmation orientée objet

En programmation orientée objet, l'utilisation des Modèle:Langue se fait en général par héritage depuis une classe mère (ou modèle de classe) générique, possédant une méthode virtuelle pure qui contiendra le code à exécuter en parallèle. Il faut et il suffit alors d'écrire la classe dérivée implémentant ce que l'on veut paralléliser, de l'instancier et d'appeler une méthode particulière (souvent nommée Modèle:Langue ou équivalent) pour démarrer le Modèle:Langue. Des méthodes d'arrêt ou d'attente de fin de tâche sont également présentes, simplifiant fortement la création de Modèle:Langue simples. Toutefois, des opérations plus complexes (barrière sur un nombre important de Modèle:Langue, réglages précis de priorité, etc.) peuvent être moins faciles qu'avec l'utilisation des Modèle:Langue natifs.

On parle de classe réentrante lorsque des instances distinctes d'une telle classe peuvent être chacune utilisées par des Modèle:Langue sans effet de bord, ce qui signifie en général une absence d'élément global ou statique dans l'implémentation de la classe. On parle aussi de classe Modèle:Langue lorsque plusieurs Modèle:Langue peuvent utiliser une seule et même instance de cette classe sans engendrer de problèmes de concurrence. Une classe Modèle:Langue est forcément réentrante, mais la réciproque est fausse.

Programmation fonctionnelle

Par nature, comme tout élément en programmation fonctionnelle est réentrant - et souvent Modèle:Langue - à quelques rares exceptions près, la mise en œuvre des Modèle:Langue est fortement simplifiée par ce paradigme. En général, la parallélisation du code ne dépend que des contrats et des séquences d'appel : <math>f(g(x))</math> requiert bien entendu de calculer <math>y=g(x)</math> avant <math>f(y)</math>, ce qui empêche de paralléliser les deux fonctions. Mais ces contraintes ne sont pas spécifiques à la programmation fonctionnelle, elles sont inhérentes à l'algorithme implémenté.

Patrons de conception (Modèle:Langue) classiques avec les Modèle:Langue

Beaucoup de patrons de conception (Modèle:Langue) peuvent bénéficier des Modèle:Langue, comme Modèle:Langue, Modèle:Langue, Modèle:Langue ou encore Modèle:Langue. De manière générale, toute passation d'information à une entité logicielle d'un Modèle:Langue peut faire l'objet de l'utilisation de Modèle:Langue.

Parmi les autres exemples classiques, on trouve :

  • les modèles maître-esclave et client-serveur :
  • un pipeline (« tube ») :
    • la tâche est découpée en diverses étapes successives et/ou opérations unitaires. Chaque Modèle:Langue réalise une des étapes et passe son résultat au suivant ;
    • plusieurs pipelines peuvent coexister afin d'accélérer encore le traitement ;
    • des traitements comme la compilation, le streaming, le traitement multimédia (décodage de vidéos par exemple) bénéficient fortement d'une implémentation utilisant des Modèle:Langue.

Confusion possible

Il ne faut pas confondre la technologie Modèle:Langue de certains processeurs Intel avec les Modèle:Langue. Cette technologie permet en effet aussi bien l'exécution simultanée de processus distincts que de Modèle:Langue. Toute machine comportant des processeurs multiples (SMP) ou des processeurs intégrant l’Modèle:Langue permet aussi bien l'exécution plus rapide de programmes utilisant des Modèle:Langue que de multiples processus.

Voir aussi

Modèle:Autres projets

Articles connexes

Liens externes

Références

<references />

Modèle:Palette Modèle:Portail