pthreads(7) | Miscellaneous Information Manual | pthreads(7) |
pthreads – Threads POSIX
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) :
En plus de la pile, POSIX.1 indique que plusieurs autres attributs sont distincts pour chaque thread, dont les suivants :
Les caractéristiques spécifiques à Linux suivantes sont également distinctes pour chaque thread :
La plupart des fonctions pthreads renvoient ̣0 en cas de succès et un numéro d'erreur en cas d'échec. Les numéros d’erreur pouvant être renvoyés ont la même signification que ceux renvoyés dans errno par les appels système conventionnels et les fonctions de la bibliothèque C. 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.
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 threads ne sont garantis d'être uniques qu'à l'intérieur d'un processus. Dans toutes les fonctions pthreads qui acceptent un identifiant de thread comme argument, par définition, cet identifiant fait référence à un thread dans le même processus que celui de l’appelant.
Le système peut réutiliser un identifiant de thread après qu'un thread qui s'est terminé a été rejoint ou qu'un thread détaché se soit terminé. POSIX précise : « Si une application essaie d’utiliser un identifiant de thread dont la durée de vie est dépassée, le comportement est indéfini. ».
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ées 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()
Une fonction pour annulations sûres asynchrones peut être appelée sans risque dans une application où l’annulation asynchrone est activée (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()
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 différé (« 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 seulement (déplacée dans la liste « may » dans POSIX.1-2008)] sigsuspend() sigtimedwait() sigwait() sigwaitinfo() sleep() system() tcdrain() usleep() [POSIX.1-2001 seulement(fonction retiré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() [Ajoutée dans POSIX.1-2008] chown() [Ajoutée dans POSIX.1-2008] closedir() closelog() ctermid() ctime() ctime_r() dbm_close() dbm_delete() dbm_fetch() dbm_nextkey() dbm_open() dbm_store() dlclose() dlopen() dprintf() [Ajoutée dans POSIX.1-2008] endgrent() endhostent() endnetent() endprotoent() endpwent() endservent() endutxent() faccessat() [Ajoutée dans POSIX.1-2008] fchmod() [Ajoutée dans POSIX.1-2008] fchmodat() [Ajoutée dans POSIX.1-2008] fchown() [Ajoutée dans POSIX.1-2008] fchownat() [Ajoutée dans POSIX.1-2008] fclose() fcntl() (pour n’importe quelle valeur de l’argument de commande) fflush() fgetc() fgetpos() fgets() fgetwc() fgetws() fmtmsg() fopen() fpathconf() fprintf() fputc() fputs() fputwc() fputws() fread() freopen() fscanf() fseek() fseeko() fsetpos() fstat() fstatat() [Ajoutée dans POSIX.1-2008] ftell() ftello() ftw() futimens() [Ajoutée dans POSIX.1-2008] fwprintf() fwrite() fwscanf() getaddrinfo() getc() getc_unlocked() getchar() getchar_unlocked() getcwd() getdate() getdelim() [Ajoutée dans POSIX.1-2008] getgrent() getgrgid() getgrgid_r() getgrnam() getgrnam_r() gethostbyaddr() [POSIX.1-2001 seulement (fonction retirée dans POSIX.1-2008)] gethostbyname() [POSIX.1-2001 seulement (fonction retirée dans POSIX.1-2008)] gethostent() gethostid() gethostname() getline() [Ajoutée dans POSIX.1-2008] getlogin() getlogin_r() getnameinfo() getnetbyaddr() getnetbyname() getnetent() getopt() (si opterr est différent de zéro) getprotobyname() getprotobynumber() getprotoent() getpwent() getpwnam() getpwnam_r() getpwuid() getpwuid_r() gets() getservbyname() getservbyport() getservent() getutxent() getutxid() getutxline() getwc() getwchar() getwd() [POSIX.1-2001 seulement (fonction retirée dans POSIX.1-2008)] glob() iconv_close() iconv_open() ioctl() link() linkat() [Ajoutée dans POSIX.1-2008] lio_listio() [Ajoutée dans POSIX.1-2008] localtime() localtime_r() lockf() [Ajoutée dans POSIX.1-2008] lseek() lstat() mkdir() [Ajoutée dans POSIX.1-2008] mkdirat() [Ajoutée dans POSIX.1-2008] mkdtemp() [Ajoutée dans POSIX.1-2008] mkfifo() [Ajoutée dans POSIX.1-2008] mkfifoat() [Ajoutée dans POSIX.1-2008] mknod() [Ajoutée dans POSIX.1-2008] mknodat() [Ajoutée dans 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() [Ajoutée dans POSIX.1-2008] psignal() [Ajoutée dans 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() [Ajoutée dans POSIX.1-2008] readlinkat() [Ajoutée dans POSIX.1-2008] remove() rename() renameat() [Ajoutée dans POSIX.1-2008] rewind() rewinddir() scandir() [Ajoutée dans POSIX.1-2008] scanf() seekdir() semop() setgrent() sethostent() setnetent() setprotoent() setpwent() setservent() setutxent() sigpause() [Ajoutée dans POSIX.1-2008] stat() strerror() strerror_r() strftime() symlink() symlinkat() [Ajoutée dans POSIX.1-2008] sync() syslog() tmpfile() tmpnam() ttyname() ttyname_r() tzset() ungetc() ungetwc() unlink() unlinkat() [Ajoutée dans POSIX.1-2008] utime() [Ajoutée dans POSIX.1-2008] utimensat() [Ajoutée dans POSIX.1-2008] utimes() [Ajoutée dans POSIX.1-2008] vdprintf() [Ajoutée dans 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 (cela inclut la plupart des fonctions qui peuvent modifier des fichiers).
Il est à remarquer que même si une application n’utilise pas d’annulation asynchrone, l’appel d’une fonction de la liste ci-dessus à partir d’un gestionnaire de signal asynchrone peut provoquer l’équivalent d’une annulation asynchrone. Le code sous-jacent de l’utilisateur peut ne pas s’attendre à une annulation asynchrone et l’état des données de l’utilisateur peut devenir incohérent. Par conséquent, les signaux doivent être utilisés avec précaution lors de l’entrée dans une région d’annulation différée.
Sous Linux, les programmes utilisant l'API pthreads doivent être compilés avec cc -pthread.
Deux implémentations différentes des threads ont été fournies par la bibliothèque C de GNU sous Linux :
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.
Les fonctionnalités importantes de cette implémentation sont les suivantes :
L'implémentation LinuxThreads s'écarte de la spécification POSIX.1 par plusieurs aspects, dont les suivants :
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. Ces signaux ne peuvent pas être utilisés dans les applications. Consulter nptl(7) pour davantage de détails.
NPTL a encore au moins une non conformité à POSIX.1 :
Certaines non conformités n'apparaissent qu'avec des noyaux plus anciens :
Veuillez noter les points suivants à propos de l'implémentation NPTL :
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
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 dynamiques. Cette variable indique à l'éditeur de liens dynamiques 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|nptl' linuxthreads-0.10 by Xavier Leroy
clone(2), fork(2), futex(2), gettid(2), proc(5), attributes(7), futex(7), nptl(7), sigevent(7), signal(7)
Diverses pages de manuel de Pthreads, par exemple : pthread_atfork(3), pthread_attr_init(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_mutexattr_destroy(3), pthread_mutexattr_init(3), pthread_once(3), pthread_spin_init(3), pthread_spin_lock(3), pthread_rwlockattr_setkind_np(3), pthread_setcancelstate(3), pthread_setcanceltype(3), pthread_setspecific(3), pthread_sigmask(3), pthread_sigqueue(3) et pthread_testcancel(3)
La traduction française de cette page de manuel a été créée par Christophe Blaess <https://www.blaess.fr/christophe/>, Stéphan Rafin <stephan.rafin@laposte.net>, Thierry Vignaud <tvignaud@mandriva.com>, François Micaux, Alain Portal <aportal@univ-montp2.fr>, Jean-Philippe Guérard <fevrier@tigreraye.org>, Jean-Luc Coulon (f5ibh) <jean-luc.coulon@wanadoo.fr>, Julien Cristau <jcristau@debian.org>, Thomas Huriaux <thomas.huriaux@gmail.com>, Nicolas François <nicolas.francois@centraliens.net>, Florentin Duneau <fduneau@gmail.com>, Simon Paillard <simon.paillard@resel.enst-bretagne.fr>, Denis Barbier <barbier@debian.org>, David Prévot <david@tilapin.org>, Frédéric Hantrais <fhantrais@gmail.com> et Jean-Paul Guillonneau <guillonneau.jeanpaul@free.fr>
Cette traduction est une documentation libre ; veuillez vous reporter à la GNU General Public License version 3 concernant les conditions de copie et de distribution. Il n'y a aucune RESPONSABILITÉ LÉGALE.
Si vous découvrez un bogue dans la traduction de cette page de manuel, veuillez envoyer un message à debian-l10n-french@lists.debian.org.
5 février 2023 | Pages du manuel de Linux 6.03 |