NOM¶
pthreads - Threads POSIX
DESCRIPTION¶
POSIX.1 décrit une série d'interfaces (fonctions et fichiers
d'en‐têtes) pour la programmation multithread, couramment
appelée threads POSIX, ou pthreads. Un unique processus peut contenir
plusieurs threads, qui exécutent tous le même programme. Ces threads
partagent la même mémoire globale (segments de données et tas),
mais chaque thread a sa propre pile (variables automatiques).
POSIX.1 requiert aussi que les threads partagent une série d'autres
attributs (ces attributs sont par processus, plutôt que par
thread) :
- -
- identifiant de processus (PID)
- -
- identifiant de processus père (PPID)
- -
- identifiant de groupe de processus (PGID) et identifiant de
session (SID)
- -
- terminal de contrôle
- -
- identifiants d'utilisateur et de groupe
- -
- descripteurs de fichier ouverts
- -
- verrouillages d'enregistrements (consultez
fcntl(2))
- -
- gestion de signaux
- -
- masque de création de fichier (umask(2))
- -
- répertoire de travail (chdir(2)) et
répertoire racine ( chroot(2))
- -
- temporisations d'intervalle (setitimer(2)) et
temporisations POSIX ( timer_create(2))
- -
- valeur de politesse (setpriority(2))
- -
- limites de ressources (setrlimit(2))
- -
- mesures de consommation de temps CPU (times(2)) et
de ressources ( getrusage(2))
En plus de la pile, POSIX.1 indique que plusieurs autres attributs sont
distincts pour chaque thread, dont les suivants :
- -
- identifiant de thread (le type de donnée
pthread_t)
- -
- masque de signaux (pthread_sigmask(3))
- -
- la variable errno
- -
- pile spécifique de signal (sigaltstack(2))
- -
- politique et priorité d'ordonnancement temps-réel
( sched_setscheduler(2) et sched_setparam(2))
Les caractéristiques spécifiques à Linux suivantes sont
également distinctes pour chaque thread :
- -
- capacités (consultez capabilities(7))
- -
- affinité CPU (sched_setaffinity(2))
Valeurs de retour des fonctions pthreads¶
La plupart des fonctions pthreads renvoient 0 en cas de succès et un
numéro d'erreur en cas d'échec. Notez que les fonctions pthreads ne
positionnent pas
errno. Pour chacune des fonctions pthreads qui peuvent
produire une erreur, POSIX.1-2001 spécifie que la fonction ne peut pas
échouer avec l'erreur
EINTR.
Identifiants de thread¶
Chacun des threads d'un processus a un unique identifiant de thread (stocké
dans le type
pthread_t). Cet identifiant est renvoyé à
l'appelant de
pthread_create(3) et un thread peut obtenir son propre
identifiant de thread en utilisant
pthread_self(3). Les identifiants de
thread n'ont la garantie d'être uniques qu'à l'intérieur d'un
processus. Un identifiant de thread peut être réutilisé
après qu'un thread qui s'est terminé a été rejoint ou
qu'un thread détaché se soit terminé. Pour toutes les fonctions
qui acceptent un identifiant de thread en paramètre, cet identifiant de
thread se réfère par définition à un thread du même
processus que l'appelant.
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 sûreté (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 et POSIX.1-2008 exigent que toutes les fonctions indiquées
dans la norme soient sûres du point de vue des threads, excepté les
fonctions suivantes :
asctime()
basename()
catgets()
crypt()
ctermid() avec un paramètre 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() [POSIX.1-2001 uniquement (fonction supprimée dans POSIX.1-2008)]
encrypt()
endgrent()
endpwent()
endutxent()
fcvt() [POSIX.1-2001 uniquement (fonction supprimée dans POSIX.1-2008)]
ftw()
gcvt() [POSIX.1-2001 uniquement (fonction supprimée dans POSIX.1-2008)]
getc_unlocked()
getchar_unlocked()
getdate()
getenv()
getgrent()
getgrgid()
getgrnam()
gethostbyaddr() [POSIX.1-2001 uniquement (fonction supprimée dans POSIX.1-2008)]
gethostbyname() [POSIX.1-2001 uniquement (fonction supprimée dans POSIX.1-2008)]
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()
strsignal() [Ajoutée dans POSIX.1-2008]
strtok()
system() [Ajoutée dans POSIX.1-2008]
tmpnam() avec un paramètre non NULL
ttyname()
unsetenv()
wcrtomb() si son dernier paramètre est NULL
wcsrtombs() si son dernier paramètre est NULL
wcstombs()
wctomb()
Fonctions pour annulations sûres asynchrones¶
Une fonction pour annulations sûres asynchrones peut être appelée
sans risque dans une application où l'état d'annulation est
activé (consultez
pthread_setcancelstate(3)).
POSIX.1-2001 et POSIX.1-2008 exigent que seules les fonctions suivantes soient
pour annulations sûres asynchrones :
pthread_cancel()
pthread_setcancelstate()
pthread_setcanceltype()
Points d'annulation¶
POSIX.1 spécifie que certaines fonctions doivent, et certaines autres
fonctions peuvent, être des points d'annulation. Si un thread est
annulable, que son type d'annulation est retardé
(« deferred ») et qu'une demande d'annulation est en cours
pour ce thread, alors le thread est annulé quand il appelle une fonction
qui est un point d'annulation.
POSIX.1-2001 et/ou POSIX.1-2008 exigent que les fonctions suivantes soient des
points d'annulation :
accept()
aio_suspend()
clock_nanosleep()
close()
connect()
creat()
fcntl() F_SETLKW
fdatasync()
fsync()
getmsg()
getpmsg()
lockf() F_LOCK
mq_receive()
mq_send()
mq_timedreceive()
mq_timedsend()
msgrcv()
msgsnd()
msync()
nanosleep()
open()
openat() [Ajoutée dans POSIX.1-2008]
pause()
poll()
pread()
pselect()
pthread_cond_timedwait()
pthread_cond_wait()
pthread_join()
pthread_testcancel()
putmsg()
putpmsg()
pwrite()
read()
readv()
recv()
recvfrom()
recvmsg()
select()
sem_timedwait()
sem_wait()
send()
sendmsg()
sendto()
sigpause() [POSIX.1-2001 uniquement (dans la liste des fonctions pouvant être un point d'annulation dans POSIX.1-2008)]
sigsuspend()
sigtimedwait()
sigwait()
sigwaitinfo()
sleep()
system()
tcdrain()
usleep() [POSIX.1-2001 uniquement (fonction supprimée dans POSIX.1-2008)]
wait()
waitid()
waitpid()
write()
writev()
POSIX.1-2001 et/ou POSIX.1-2008 indiquent que les fonctions suivantes peuvent
être des points d'annulation :
access()
asctime()
asctime_r()
catclose()
catgets()
catopen()
chmod() [Added in POSIX.1-2008]
chown() [Added in POSIX.1-2008]
closedir()
closelog()
ctermid()
ctime()
ctime_r()
dbm_close()
dbm_delete()
dbm_fetch()
dbm_nextkey()
dbm_open()
dbm_store()
dlclose()
dlopen()
dprintf() [Added in POSIX.1-2008]
endgrent()
endhostent()
endnetent()
endprotoent()
endpwent()
endservent()
endutxent()
faccessat() [Added in POSIX.1-2008]
fchmod() [Added in POSIX.1-2008]
fchmodat() [Added in POSIX.1-2008]
fchown() [Added in POSIX.1-2008]
fchownat() [Added in POSIX.1-2008]
fclose()
fcntl() (for any value of cmd argument)
fflush()
fgetc()
fgetpos()
fgets()
fgetwc()
fgetws()
fmtmsg()
fopen()
fpathconf()
fprintf()
fputc()
fputs()
fputwc()
fputws()
fread()
freopen()
fscanf()
fseek()
fseeko()
fsetpos()
fstat()
fstatat() [Added in POSIX.1-2008]
ftell()
ftello()
ftw()
futimens() [Added in POSIX.1-2008]
fwprintf()
fwrite()
fwscanf()
getaddrinfo()
getc()
getc_unlocked()
getchar()
getchar_unlocked()
getcwd()
getdate()
getdelim() [Added in POSIX.1-2008]
getgrent()
getgrgid()
getgrgid_r()
getgrnam()
getgrnam_r()
gethostbyaddr() [SUSv3 only (function removed in POSIX.1-2008)]
gethostbyname() [SUSv3 only (function removed in POSIX.1-2008)]
gethostent()
gethostid()
gethostname()
getline() [Added in POSIX.1-2008]
getlogin()
getlogin_r()
getnameinfo()
getnetbyaddr()
getnetbyname()
getnetent()
getopt() (if opterr is nonzero)
getprotobyname()
getprotobynumber()
getprotoent()
getpwent()
getpwnam()
getpwnam_r()
getpwuid()
getpwuid_r()
gets()
getservbyname()
getservbyport()
getservent()
getutxent()
getutxid()
getutxline()
getwc()
getwchar()
getwd() [SUSv3 only (function removed in POSIX.1-2008)]
glob()
iconv_close()
iconv_open()
ioctl()
link()
linkat() [Added in POSIX.1-2008]
lio_listio() [Added in POSIX.1-2008]
localtime()
localtime_r()
lockf() [Added in POSIX.1-2008]
lseek()
lstat()
mkdir() [Added in POSIX.1-2008]
mkdirat() [Added in POSIX.1-2008]
mkdtemp() [Added in POSIX.1-2008]
mkfifo() [Added in POSIX.1-2008]
mkfifoat() [Added in POSIX.1-2008]
mknod() [Added in POSIX.1-2008]
mknodat() [Added in POSIX.1-2008]
mkstemp()
mktime()
nftw()
opendir()
openlog()
pathconf()
pclose()
perror()
popen()
posix_fadvise()
posix_fallocate()
posix_madvise()
posix_openpt()
posix_spawn()
posix_spawnp()
posix_trace_clear()
posix_trace_close()
posix_trace_create()
posix_trace_create_withlog()
posix_trace_eventtypelist_getnext_id()
posix_trace_eventtypelist_rewind()
posix_trace_flush()
posix_trace_get_attr()
posix_trace_get_filter()
posix_trace_get_status()
posix_trace_getnext_event()
posix_trace_open()
posix_trace_rewind()
posix_trace_set_filter()
posix_trace_shutdown()
posix_trace_timedgetnext_event()
posix_typed_mem_open()
printf()
psiginfo() [Added in POSIX.1-2008]
psignal() [Added in POSIX.1-2008]
pthread_rwlock_rdlock()
pthread_rwlock_timedrdlock()
pthread_rwlock_timedwrlock()
pthread_rwlock_wrlock()
putc()
putc_unlocked()
putchar()
putchar_unlocked()
puts()
pututxline()
putwc()
putwchar()
readdir()
readdir_r()
readlink() [Added in POSIX.1-2008]
readlinkat() [Added in POSIX.1-2008]
remove()
rename()
renameat() [Added in POSIX.1-2008]
rewind()
rewinddir()
scandir() [Added in POSIX.1-2008]
scanf()
seekdir()
semop()
setgrent()
sethostent()
setnetent()
setprotoent()
setpwent()
setservent()
setutxent()
sigpause() [Added in POSIX.1-2008]
stat()
strerror()
strerror_r()
strftime()
symlink()
symlinkat() [Added in POSIX.1-2008]
sync()
syslog()
tmpfile()
tmpnam()
ttyname()
ttyname_r()
tzset()
ungetc()
ungetwc()
unlink()
unlinkat() [Added in POSIX.1-2008]
utime() [Added in POSIX.1-2008]
utimensat() [Added in POSIX.1-2008]
utimes() [Added in POSIX.1-2008]
vdprintf() [Added in POSIX.1-2008]
vfprintf()
vfwprintf()
vprintf()
vwprintf()
wcsftime()
wordexp()
wprintf()
wscanf()
Une implémentation peut également indiquer d'autres fonctions non
spécifiées dans la norme comme étant des points d'annulation.
En particulier, une implémentation marquera probablement toute fonction
non standard qui peut bloquer comme étant un point d'annulation (ceci
inclus la plupart des fonctions qui peuvent toucher des fichiers).
Compiler sous Linux¶
Sous Linux, les programmes utilisant l'API pthreads doivent être
compilés avec
cc -pthread.
Implémentations des threads POSIX sous Linux¶
Deux implémentations différentes des threads ont été
fournies par la bibliothèque C de GNU sous Linux :
- LinuxThreads
- Il s'agit de l'implémentation des Pthreads originelle.
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 moderne des Pthreads.
Par rapport à LinuxThreads, NPTL se conforme mieux aux exigences de
la norme POSIX.1, et une meilleure performance lors de la création
d'un grand nombre de threads. NPTL est disponible depuis la
glibc 2.3.2, et nécessite des fonctionnalités
présentes dans le noyau Linux 2.6.
Ces deux implémentation sont dit de type 1:1, ce qui veut dire que chaque
thread correspond à une entité d'ordonnancement du noyau. Les deux
implémentations utilisent l'appel système
clone(2) de Linux.
Dans NPTL, les primitives de synchronisation de threads (mutexes, jonction de
thread, etc.) sont implémentées avec l'appel système
futex(2) de Linux.
LinuxThreads¶
Les fonctionnalités importantes de cette implémentation sont les
suivantes :
- -
- En plus du thread principal (initial) et des threads
créés par le programme avec pthread_create(3),
l'implémentation crée un thread de gestion. Ce thread s'occupe
de la création et de la terminaison des threads. Des problèmes
peuvent survenir si ce thread est tué de façon
imprévue.
- -
- Les signaux sont utilisés en interne par
l'implémentation. Sous Linux 2.2 et suivants, les trois premiers
signaux temps-réel sont utilisés (voir aussi signal(7)).
Sous les noyaux plus anciens, LinuxThreads utilise SIGUSR1 et
SIGUSR2. Les applications doivent éviter d'utiliser les
signaux utilisés par l'implémentation.
- -
- Les threads ne partagent pas leur identifiant de processus.
(En fait, les threads LinuxThreads sont implémentés comme des
processus partageant plus d'informations qu'à l'habitude, mais pas
leur identifiant de processus.) Les threads LinuxThreads (y compris le
thread de gestion) sont visibles comme des processus différents avec
ps(1).
L'implémentation LinuxThreads s'écarte de la spécification
POSIX.1 par plusieurs aspects, dont les suivants :
- -
- Les appels à getpid(2) renvoient une valeur
distincte dans chaque thread.
- -
- Les appels à getppid(2) dans les threads autres
que le thread principal renvoient l'identifiant de processus du thread de
gestion ; getppid(2) dans ces threads devrait renvoyer la
même valeur que dans le thread principal.
- -
- Lorsqu'un thread crée un nouveau processus fils avec
fork(2), n'importe quel thread devrait pouvoir utiliser
wait(2) pour attendre la terminaison de ce fils. Cependant,
l'implémentation ne permet qu'au thread ayant créé le fils
d'appeler wait(2) pour l'attendre.
- -
- Lorsqu'un thread appelle execve(2), tous les autres
threads sont terminés (comme le prescrit POSIX.1). Cependant, le
processus résultant a le même PID que le thread ayant
appelé execve(2) : il devrait avoir le même PID que
le thread principal.
- -
- Les threads ne partagent pas leurs identifiants
d'utilisateur et de groupe. Ceci peut causer des complications pour les
programmes setuid et provoquer des erreurs dans les fonctions pthreads si
une application change d'identifiant avec seteuid(2) et
consorts.
- -
- Les threads ne partagent pas l'identifiant de session et de
groupe de processus.
- -
- Les threads ne partagent pas les verrouillages
d'enregistrements créés avec fcntl(2).
- -
- L'information renvoyée par times(2) et
getrusage(2) est par thread au lieu d'être par processus.
- -
- Les threads ne partagent pas les valeurs
« undo » de sémaphores (voir
semop(2)).
- -
- Les threads ne partagent pas les temporisations
d'intervalles.
- -
- Les threads ne partagent pas leur valeur de politesse.
- -
- POSIX.1 distingue les notions de signal envoyé au
processus dans son ensemble, et de signal envoyé à un thread
individuellement. Selon POSIX.1, un signal envoyé au processus (par
exemple avec kill(2)) sera géré par un thread choisi
arbitrairement au sein du processus. LinuxThreads ne permet pas d'envoyer
un signal au processus, mais seulement à un thread
spécifique.
- -
- Les threads ont des paramètres de pile spécifique
de signal distincts. Cependant, les paramètres de pile
spécifique d'un nouveau thread sont copiés à partir du
thread qui l'a créé, ce qui veut dire que les threads partagent
initialement une même pile spécifique de signaux. (Un nouveau
thread devrait démarrer sans pile spécifique de signaux. Si deux
threads gèrent un signal sur leur pile spécifique au même
moment, des échecs imprévisibles du programme risquent de se
produire.)
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 de gestion. NPTL utilise en
interne les deux premiers signaux temps‐réel (voir aussi
signal(7)) ; ces signaux ne peuvent pas être utilisés
dans les applications.
NPTL a encore au moins une non conformité à POSIX.1 :
- -
- Les threads ne partagent pas leur valeur de politesse.
Certaines non conformités n'apparaissent qu'avec des noyaux plus
anciens :
- -
- L'information renvoyée par times(2) et
getrusage(2) est par thread au lieu d'être globale au
processus (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 temporisations
d'intervalles (corrigé dans le noyau 2.6.12).
- -
- Seul le thread principal est autorisé à
démarrer une nouvelle session avec setsid(2) (corrigé
dans le noyau 2.6.16).
- -
- Seul le thread principal est autorisé à rendre le
processus leader de son groupe de processus avec setpgid(2)
(corrigé dans le noyau 2.6.16).
- -
- Les threads ont des paramètres de pile spécifique
de signaux distincts. Cependant, les paramètres de pile
spécifique d'un nouveau thread sont copiés sur ceux du thread
qui l'a créé, et les threads partagent donc initialement leur
pile spécifique de signaux (corrigé dans le
noyau 2.6.16).
Veuillez noter les points suivants à propos de l'implémentation
NPTL :
- -
- Si la limite souple de taille de pile (voir dans
setrlimit(2) la description de RLIMIT_STACK) est
différente de unlimited, cette valeur détermine la taille
de pile par défaut pour les nouveaux threads. Pour avoir un effet,
cette limite doit être définie avant le démarrage du
programme, par exemple en utilisant la commande ulimit -s du shell
( limit stacksize dans csh).
Déterminer l'implémentation des threads
utilisée¶
Depuis glibc 2.3.2, la commande
getconf(1) peut être
utilisée pour déterminer l'implémentation de threads du
système, par exemple :
bash$ getconf GNU_LIBPTHREAD_VERSION
NPTL 2.3.4
Avec des versions plus anciennes de la glibc, une commande comme la suivante
devrait être suffisante pour déterminer l'implémentation de
threads par défaut :
bash$ $( ldd /bin/ls | grep libc.so | awk '{print $3}' ) | \
egrep -i 'threads|nptl'
Native POSIX Threads Library by Ulrich Drepper et al
Choisir l'implémentation des threads :
LD_ASSUME_KERNEL¶
Sur les systèmes avec une glibc fournissant à la fois LinuxThreads et
NPTL (i.e. glibc 2.3.
x), la variable d'environnement
LD_ASSUME_KERNEL peut être utilisée pour écraser le
choix par défaut d'implémentation de threads fait par l'éditeur
de liens dynamique. Cette variable indique à l'éditeur de liens
dynamique qu'il doit faire comme s'il était exécuté avec une
version particulière du noyau. En indiquant une version du noyau ne
fournissant pas les fonctionnalités nécessitées par NPTL, on
peut forcer l'utilisation de LinuxThreads. (La raison la plus probable pour
cela est d'exécuter une application (boguée) qui dépend d'un
comportement de LinuxThreads non conforme à la spécification.) 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),
proc(5),
futex(7),
sigevent(7),
signal(7),
Diverses pages de manuel Pthreads, par exemple :
pthread_attr_init(3),
pthread_atfork(3),
pthread_cancel(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),
pthread_sigqueue(3) et
pthread_testcancel(3)
COLOPHON¶
Cette page fait partie de la publication 3.44 du projet
man-pages Linux.
Une description du projet et des instructions pour signaler des anomalies
peuvent être trouvées à l'adresse
<
http://www.kernel.org/doc/man-pages/>.
TRADUCTION¶
Depuis 2010, cette traduction est maintenue à l'aide de l'outil po4a
<
http://po4a.alioth.debian.org/> par l'équipe de traduction
francophone au sein du projet perkamon
<
http://perkamon.alioth.debian.org/>.
Christophe Blaess <
http://www.blaess.fr/christophe/> (1996-2003), Alain
Portal <
http://manpagesfr.free.fr/> (2003-2006). Julien Cristau et
l'équipe francophone de traduction de Debian (2006-2009).
Veuillez signaler toute erreur de traduction en écrivant à
<debian-l10n-french@lists.debian.org> ou par un rapport de bogue sur le
paquet
manpages-fr.
Vous pouvez toujours avoir accès à la version anglaise de ce document
en utilisant la commande «
man -L C
<section> <page_de_man> ».