PTHREADS

Section : Manuel du programmeur Linux (7)
Mise à jour de la version anglaise : 29 mai 2008
Index Menu principal  

NOM

pthreads - Threads POSIX  

DESCRIPTION

POSIX.1 spécifie un ensemble d'interfaces (fonctions, fichiers d'entê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 « courtoisie » (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 fonctionnalités suivantes, spécifiques à Linux, sont également par thread :

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

Fonctions sûres du point de vue des threads

Une fonction sûre du point de vue des threads est une fonction qui peut être appelée en toute sureté (c'est-à-dire qu'elle renverra le même résultat d'où qu'elle soit appelée) par plusieurs threads en même temps.

POSIX.1-2001 réclame que toutes les fonctions indiquées dans la norme soit sûres du point de vue des threads, excepté les fonctions suivantes :


asctime()
basename()
catgets()
crypt()
ctermid() s'il lui est passé un argument non-NULL
ctime()
dbm_clearerr()
dbm_close()
dbm_delete()
dbm_error()
dbm_fetch()
dbm_firstkey()
dbm_nextkey()
dbm_open()
dbm_store()
dirname()
dlerror()
drand48()
ecvt()
encrypt()
endgrent()
endpwent()
endutxent()
fcvt()
ftw()
gcvt()
getc_unlocked()
getchar_unlocked()
getdate()
getenv()
getgrent()
getgrgid()
getgrnam()
gethostbyaddr()
gethostbyname()
gethostent()
getlogin()
getnetbyaddr()
getnetbyname()
getnetent()
getopt()
getprotobyname()
getprotobynumber()
getprotoent()
getpwent()
getpwnam()
getpwuid()
getservbyname()
getservbyport()
getservent()
getutxent()
getutxid()
getutxline()
gmtime()
hcreate()
hdestroy()
hsearch()
inet_ntoa()
l64a()
lgamma()
lgammaf()
lgammal()
localeconv()
localtime()
lrand48()
mrand48()
nftw()
nl_langinfo()
ptsname()
putc_unlocked()
putchar_unlocked()
putenv()
pututxline()
rand()
readdir()
setenv()
setgrent()
setkey()
setpwent()
setutxent()
strerror()
strtok()
tmpnam() s'il lui est passé un argument non-NULL
ttyname()
unsetenv()
wcrtomb() si son dernier argument est NULL
wcsrtombs() si son dernier argument est NULL
wcstombs()
wctomb()
 

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 glibc :
LinuxThreads
Il s'agit de l'implémentation Pthreads originale. Depuis la glibc 2.4, cette implémentation n'est plus prise en charge.
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 est disponible depuis la glibc 2.3.2 et nécessite des fonctionnalité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).  

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 « courtoisie » 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 au moins une non-conformité 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 souple 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éterminer l'implémentation de threading 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 aq{print $3}aq ) | \
                egrep -i aqthreads|nptlaq
        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 (c'est-à-dire la glibc 2.3.x), 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 17 juillet 2008.

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.

 

Index

NOM
DESCRIPTION
Fonctions sûres du point de vue des threads
Compilation sous Linux
Implémentations Linux des threads POSIX
LinuxThreads
NPTL
Déterminer l'implémentation de threading
Sélectionner l'implémentation de threading : LD_ASSUME_KERNEL
VOIR AUSSI
TRADUCTION

Dernière mise à jour : 17 juillet 2008