pthreads

Autres langues

Langue: fr

Version: 7 juin 2005 (mandriva - 01/05/08)

Section: 7 (Divers)

NOM

pthreads - Threads POSIX

DESCRIPTION

POSIX.1 spécifie un ensemble d'interfaces (fonctions, fichiers d'en-tête) pour la programmation par thread, plus connu sous le nom de threads POSIX ou Pthreads. Un seul processus peut contenir plusieurs threads, chacun d'eux exécutant le même programme. Ces threads partagent la même mémoire globale (segments de données et de tas) mais chaque thread possède sa propre pile (variables automatiques).

POSIX.1 réclame également que les threads partagent un ensemble d'autres attributs (c'est-à-dire que ces attributs sont à l'échelle du processus plutôt que spécifiques à chaque thread) :

-
ID du processus (PID)
-
ID du processus parent (PPID)
-
ID du groupe du processus (PGID) et ID de session
-
terminal de contrôle
-
ID utilisateur (UID) et ID de groupe (GID)
-
descripteurs de fichier ouverts
-
verrous d'enregistrement (voir fcntl(2))
-
dispositions de signaux
-
masque de création de fichier (umask(2))
-
répertoire courant (chdir(2)) et répertoire racine (chroot(2))
-
temporisateurs d'intervalle (setitimer(2)) et temporisateurs POSIX (timer_create(3))
-
valeur de « gentillesse » (setpriority(2))
-
limites des ressources (setrlimit(2))
-
mesures de la consommation de temps CPU (times(2)) et de ressources (getrusage(2))

En plus de la pile, POSIX.1 spécifie divers autres attributs propres à chaque thread, incluant :

-
ID de thread (TID) (le type de donnée pthread_t)
-
masque de signaux (pthread_sigmask(3))
-
la variable errno
-
pile de signal alternative (sigaltstack(2))
-
politique et priorité d'ordonnacement temps réel (sched_setscheduler(2) et sched_setparam(2))

Les fonctionalités suivantes, spécifiques à Linux, sont également par thread :

-
capacités (voir capabilities(7))
-
affinité CPU (sched_setaffinity(2))

Compilation sous Linux

Sous Linux, les programmes qui utilisent l'API Pthreads devraient être compilés en utilisant la commande cc -pthread.

Implémentations Linux des threads POSIX

Sous Linux, deux implémentations de threading sont fournies par la bibliothèque C GNU :
-
LinuxThreads Il s'agit de l'implémentation Pthreads originale (à présent obsolète).
-
NPTL (Native POSIX Threads Library) Il s'agit de l'implémentation Pthreads moderne. En comparaison avec LinuxThreads, NPTL fournit une conformité plus proche des spécifications POSIX.1 et une meilleure performance lorsque l'on crée un grand nombre de threads. NPTL nécessite des fonctionalités qui sont présentes dans le noyau Linux 2.6.

Toutes les deux sont appelées implémentations 1:1, signifiant que chaque thread correspond à une entité d'ordonnacement noyau.

Les deux implémentations utilisent l'appel système Linux clone(2).

Dans la bibliothèque NPTL, les primitives de synchronisation de thread (mutexes, attachement de thread, etc.) sont implémentées en utilisant l'appel système Linux futex(2).

Les bibliothèques C GNU modernes fournissent les deux bibliothèques, LinuxThreads et NPTL, la dernière étant celle par défaut (si elle est supportée par le noyau sous-jacent).

LinuxThreads

Les fonctionnalités notables de cette implémentation sont les suivantes :
-
En plus du thread principal (initial) et des threads que le programme crée avec pthread_create(3), l'implémentation crée un thread « gestionnaire ». Ce thread gère la création et la terminaison des threads. (Des problèmes peuvent survenir si ce thread est tué par inadvertance.)
-
Les signaux sont utilisés de manière interne par l'implémentation. Sous Linux 2.2 et suivants, les trois premiers signaux temps réel sont utilisés. Sur les noyaux plus anciens, SIGUSR1 et SIGUSR2 sont utilisés. Les applications doivent éviter d'utiliser les signaux qui le sont par l'implémentation.
-
Les threads ne partagent pas les PID. (En effet, les threads LinuxThreads sont implémentés comme des processus qui partagent plus d'informations qu'à l'habitude, mais qui ne partagent pas un PID commun.) Les threads LinuxThreads (y compris le thread gestionnaire) sont visibles en tant que processus séparés lorsqu'on utilise ps(1).

L'implémentation LinuxThreads dévie des spécifications POSIX.1 de plusieurs façons, incluant :

-
Les appels à getpid(2) renvoient une valeur différente dans chaque thread.
-
Les appels à getppid(2) dans les threads autres que le thread principal renvoient le PID du thread gestionnaire ; à la place, getppid(2) dans ces threads devrait retourner la même valeur que getppid(2) dans le thread principal.
-
Lorsqu'un thread crée un nouveau processus fils avec fork(2), chaque thread devrait être capable d'attendre (wait(2)) le fils. Toutefois, l'implémentation ne permet qu'au thread qui a créé le fils de l'attendre.
-
Lorsqu'un thread appelle execve(2), tous les autres threads sont terminés (comme requis par POSIX.1). Toutefois, le processus résultant a le même PID que le thread qui a appelé execve(2) : il devrait avoir le même PID que le thread principal.
-
Les threads ne partagent pas les UID et GID. Cela peut provoquer des complications avec les programmes Set-UID et provoquer des échecs dans les fonctions Pthreads si une application modifie ses références avec seteuid(2) ou une fonction similaire.
-
Les threads ne partagent pas un PGID et un ID de session commun.
-
Les threads ne partagent pas les verrous d'enregistrement créés avec fcntl(2).
-
Les informations renvoyées par times(2) et getrusage(2) sont par thread et non à l'échelle du processus.
-
Les threads ne partagent pas les valeurs « undo » des sémaphores (voir semop(2)).
-
Les threads ne partagent pas les temporisateurs d'intervalles.
-
Les threads ne partagent pas une valeur de « gentillesse » commune.
-
POSIX.1 distingue les notions de signaux qui s'adressent au processus dans son ensemble et des signaux qui s'adressent aux threads de manière individuelle. Suivant POSIX.1, un signal s'adressant à un processus (envoyé par kill(2), par exemple) devrait être géré par un seul thread, choisi arbitrairement dans le processus. LinuxThreads ne supporte pas la notion de signaux s'adressant à un processus : les signaux peuvent seulement être envoyés à des threads spécifiques.
-
Tous les threads ont des configurations distinctes pour les piles utilisées spécifiquement lors du traitement des signaux. Toutefois, la configuration d'un thread nouvellement créé est copiée sur la configuration de son créateur, aussi partagent-ils la même pile spécifique pour les signaux. (Il serait préférable qu'un nouveau thread démarre sans pile de traitement de signaux, car si deux threads gèrent des signaux en utilisant la même pile, on assistera probablement à des plantages imprévisibles.)

NPTL

Avec NPTL, tous les threads d'un processus sont placés dans le même groupe de threads ; tous les membres d'un groupe de threads partagent le même PID. NPTL n'utilise pas de thread gestionnaire. NPTL utilise de manière interne les deux premiers signaux temps réel ; ces signaux ne doivent donc pas être utilisés dans l'application.

NPTL a aussi quelques non conformités avec POSIX.1 :

-
Les threads ne partagent pas une valeur de courtoisie commune.

Certaines non conformités NPTL peuvent apparaîtrent sur d'anciens noyaux :

-
Les informations renvoyées par times(2) et getrusage(2) sont spécifiques aux threads plutôt que d'être à l'échelle du système (corrigé dans le noyau 2.6.9).
-
Les threads ne partagent pas les limites de ressources (corrigé dans le noyau 2.6.10).
-
Les threads ne partagent pas les temporisateurs d'intervalles (corrigé dans le noyau 2.6.12).
-
Seul le thread principal a le droit de démarrer une nouvelle session avec setsid(2) (corrigé dans le noyau 2.6.16).
-
Seul le thread principal a le droit de faire d'un processus un leader dans un groupe de processus avec setpgid(2) (corrigé dans le noyau 2.6.16).
-
Tous les threads ont des configurations distinctes pour les piles utilisées spécifiquement lors du traitement des signaux. Toutefois, la configuration d'un thread nouvellement créé est copiée sur la configuration de son créateur, aussi partagent-ils la même pile spécifique pour les signaux (corrigé dans le noyau 2.6.16).

Veuillez noter les points suivants concernant l'implémentation NPTL :

-
Si la limite de ressource logicielle de taille de pile (voir la description de RLIMIT_STACK dans setrlimit(2)) est définie à une valeur autre que unlimited, cette valeur définit la taille par défaut de la pile pour les nouveaux threads. Pour être effective, cette limite doit être définie avant que le programme ne soit exécuté, peut-être en utilisant la commande shell intégrée ulimit -s (limit stacksize dans le shell C).

Déterminer l'implémentation de threading

Depuis la glibc 2.3.2, la commande getconf(1) permet de détermnier l'implémentation de threading par défaut du système, par exemple :
 
 bash$ getconf GNU_LIBPTHREAD_VERSION
 NPTL 2.3.4
 

Pour les versions plus anciennes de la glibc, une commande telle la suivante devrait être suffisante pour déterminer l'implémentation de threading :

 
 bash$ $( ldd /bin/ls | grep libc.so | awk '{print $3}' ) | \
                 egrep -i 'threads|ntpl'
         Native POSIX Threads Library by Ulrich Drepper et al
 

Sélectionner l'implémentation de threading : LD_ASSUME_KERNEL

Sur les systèmes dont la glibc supportent LinuxThreads et NPTL, la variable d'environnement LD_ASSUME_KERNEL peut être utilisée pour surcharger le choix par défaut de l'implémention de threading par l'éditeur de liens dynamique. Cette variable indique à l'éditeur de liens dynamique de supposer que l'on utilise une version particulière du noyau. En spécifiant une version qui ne fournit pas le support nécessaire à NPTL, on force l'utilisation de LinuxThreads. (La principale raison pour faire cela est de lancer une application qui dépend de certains comportements non conformes de LinuxThreads.) Par exemple :
 
 bash$ $( LD_ASSUME_KERNEL=2.2.5 ldd /bin/ls | grep libc.so | \
                 awk '{print $3}' ) | egrep -i 'threads|ntpl'
         linuxthreads-0.10 by Xavier Leroy
 

VOIR AUSSI

clone(2), futex(2), gettid(2), futex(7), et diverses pages de manuel Pthreads, par exemple : pthread_atfork(3), pthread_cleanup_push(3), pthread_cond_signal(3), pthread_cond_wait(3), pthread_create(3), pthread_detach(3), pthread_equal(3), pthread_exit(3), pthread_key_create(3), pthread_kill(3), pthread_mutex_lock(3), pthread_mutex_unlock(3), pthread_once(3), pthread_setcancelstate(3), pthread_setcanceltype(3), pthread_setspecific(3), pthread_sigmask(3), et pthread_testcancel(3).

TRADUCTION

Ce document est une traduction réalisée par Alain Portal <aportal AT univ-montp2 DOT fr> le 27 juin 2006 et révisée le 28 novembre 2007.

L'équipe de traduction a fait le maximum pour réaliser une adaptation française de qualité. La version anglaise la plus à jour de ce document est toujours consultable via la commande : « LANG=C man 7 pthreads ». N'hésitez pas à signaler à l'auteur ou au traducteur, selon le cas, toute erreur dans cette page de manuel.