pthread_create(3)

NOM
pthread_create – Créer un nouveau thread

BIBLIOTHÈQUE
Bibliothèque de threads POSIX (libpthread, -lpthread)

SYNOPSIS
#include <pthread.h>

int pthread_create(pthread_t *restrict thread,
                   const pthread_attr_t *restrict attr,
                   void *(*start_routine)(void *),
                   void *restrict arg);

DESCRIPTION
La fonction pthread_create() démarre un nouveau thread (processus léger) dans le processus appelant. Le nouveau thread commence par appeler start_routine() ; arg est passé comme unique argument de start_routine().

Le nouveau thread se termine d'une des manières suivantes :

-   Il appelle pthread_exit(3), en indiquant une valeur de sortie qui sera disponible pour un autre thread du même processus qui appelle pthread_join(3).

-   Il sort de la routine start_routine(). C'est équivalent à appeler pthread_exit(3) avec la valeur fournie à l'instruction return.

-   Il est annulé (voir pthread_cancel(3)).

-   Un des threads du processus appelle exit(3) ou le thread principal sort de la routine main() ce qui entraîne l'arrêt de tous les threads du processus.

L'argument attr pointe sur une structure pthread_attr_t dont le contenu est utilisé pendant la création des threads pour déterminer les attributs du nouveau thread. Cette structure est initialisée avec pthread_attr_init(3) et les fonctions similaires. Si attr est NULL, alors le thread est créé avec les attributs par défaut.

Avant de rendre la main, un appel réussi à pthread_create() stocke l'identifiant du nouveau thread dans le tampon pointé par thread. Cet identifiant est utilisé pour se référer à ce thread dans les appels ultérieurs aux autres fonctions de pthreads.

Le nouveau thread hérite d'une copie du masque de signal du thread créateur (pthread_sigmask(3)). L'ensemble des signaux en attente pour le nouveau thread est vide (sigpending(2)). Le nouveau thread n'hérite pas de la pile spécifique de signaux (sigaltstack(2)) du thread appelant.

Le nouveau thread hérite de l'environnement en virgule flottante (fenv(3)) du thread appelant.

La valeur initiale de l'horloge CPU du nouveau thread est 0 (voir pthread_getcpuclockid(3)).

  Détails spécifiques à Linux
Le nouveau thread hérite de copies des ensembles des capacités (voir capabilities(7)) et des masques d'affinité CPU (consultez sched_setaffinity(2)) du thread appelant.

VALEUR RENVOYÉE
En cas de réussite, pthread_create() renvoie 0 ; en cas d'erreur, elle renvoie un numéro d'erreur, et le contenu de *thread est indéfini.

ERREURS

EAGAIN
    Ressources insuffisantes pour créer un nouveau thread.

EAGAIN
    Une limite système sur le nombre de threads a été atteinte. Plusieurs limites pourraient déclencher cette erreur : la limite de ressources souple RLIMIT_NPROC (définie à l’aide setrlimit(2)), qui limite le nombre de processus et threads par identifiant d’utilisateur réel, a été atteinte ; la limite système imposée par le noyau sur le nombre total de processus et threads, /proc/sys/kernel/threads-max, a été atteinte (consultez proc(5)) ; ou le nombre maximal de PID, /proc/sys/kernel/pid_max, a été atteint (consultez proc(5)).

EINVAL
    Paramètres incorrects dans attr.

EPERM
    Permissions insuffisantes pour définir la politique d'ordonnancement et les paramètres spécifiés dans attr.

ATTRIBUTS
Pour une explication des termes utilisés dans cette section, consulter attributes(7).
Interface | Attribut | Valeur
pthread_create() | Sécurité des threads | MT-Safe

STANDARDS
POSIX.1-2008.

HISTORIQUE
POSIX.1-2001.

NOTES
Consultez pthread_self(3) pour des informations plus détaillées sur l'identifiant de thread renvoyé dans *thread par pthread_create(). Sauf si une politique d'ordonnancement temps-réel est employée, après un appel à pthread_create(), on ne sait pas quel thread — l'appelant ou le nouveau thread — sera exécuté ensuite.

Un thread peut être dans un état soit joignable (joinable), soit détaché (detached). Si un thread est joignable, un autre thread peut appeler pthread_join(3) pour attendre que ce thread se termine et récupérer sa valeur de sortie. Ce n'est que quand un thread terminé et joignable a été joint que ses ressources sont rendues au système. Quand un thread détaché se termine, ses ressources sont automatiquement rendues au système : il n'est pas possible de joindre un tel thread afin d'en obtenir la valeur de sortie. Mettre un thread dans l'état détaché est pratique pour certains types de threads de démon dont l'application n'a pas à se préoccuper de la valeur de sortie. Par défaut, un nouveau thread est créé dans l'état joignable, à moins qu'attr n'ait été modifié (avec pthread_attr_setdetachstate(3)) pour créer le thread dans un état détaché.

Under the NPTL threading implementation, if the RLIMIT_STACK soft resource limit at the time the program started has any value other than "unlimited", then it determines the default stack size of new threads. Using pthread_attr_setstacksize(3), the stack size attribute can be explicitly set in the attr argument used to create a thread, in order to obtain a stack size other than the default. If the RLIMIT_STACK resource limit is set to "unlimited", a per-architecture value is used for the stack size: 2 MB on most architectures; 4 MB on POWER and Sparc-64.

BOGUES
Dans l'implémentation obsolète LinuxThreads, chacun des threads dans un processus a un identifiant de processus différent, ce qui est en violation des spécifications POSIX sur les threads et est la cause de nombreuses non-conformité au standard. Consultez pthreads(7).

EXEMPLES
Le programme ci-dessous montre l'utilisation de pthread_create(), ainsi qu'un certain nombre d'autres fonctions de l'API pthreads.

Lors de l'exécution suivante, sur un système avec l'implémentation NPTL, la taille de la pile vaut par défaut la valeur renvoyée par la limite de la ressource « stack size » (taille de la pile) :

    $ ulimit -s
    8192            # The stack size limit is 8 MB (0x800000 bytes)
    $ ./a.out hola salut servus
    Thread 1: top of stack near 0xb7dd03b8; argv_string=hola
    Thread 2: top of stack near 0xb75cf3b8; argv_string=salut
    Thread 3: top of stack near 0xb6dce3b8; argv_string=servus
    Joined with thread 1; returned value was HOLA
    Joined with thread 2; returned value was SALUT
    Joined with thread 3; returned value was SERVUS

Lors de l'exécution suivante, le programme définit explicitement une taille de pile de 1 Mo (avec pthread_attr_setstacksize(3)) pour les threads créés :

    $ ./a.out -s 0x100000 hola salut servus
    Thread 1: top of stack near 0xb7d723b8; argv_string=hola
    Thread 2: top of stack near 0xb7c713b8; argv_string=salut
    Thread 3: top of stack near 0xb7b703b8; argv_string=servus
    Joined with thread 1; returned value was HOLA
    Joined with thread 2; returned value was SALUT
    Joined with thread 3; returned value was SERVUS

  Source du programme
    #include <ctype.h>
    #include <errno.h>
    #include <pthread.h>
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <unistd.h>

    #define handle_error_en(en, msg) \
            do { errno = en; perror(msg); exit(EXIT_FAILURE); } while (0)

    #define handle_error(msg) \
            do { perror(msg); exit(EXIT_FAILURE); } while (0)

    struct thread_info {    /* Utilisé comme argument pour thread_start() */
        pthread_t thread_id;        /* Identifiant renvoyé par pthread_create() */
        int       thread_num;       /* N° de thread défini par l'application */
        char     *argv_string;      /* À partir de l'argument en ligne de commande */
    };

    /* Fonction de démarrage du thread : affiche l'adresse vers le haut de la pile,
       et renvoie une copie en majuscule de argv_string. */

    static void *
    thread_start(void *arg)
    {
        struct thread_info *tinfo = arg;
        char *uargv;

        printf("Thread %d : sommet de la pile près de %p; argv_string=%s\n",
               tinfo->thread_num, (void *) &tinfo, tinfo->argv_string);

        uargv = strdup(tinfo->argv_string);
        if (uargv == NULL)
            handle_error("strdup");

        for (char *p = uargv; *p != '\0'; p++)
            *p = toupper(*p);

        return uargv;
    }

    int
    main(int argc, char *argv[])
    {
        int                 s, opt;
        void                *res;
        size_t              num_threads;
        ssize_t             stack_size;
        pthread_attr_t      attr;
        struct thread_info  *tinfo;

        /* L'option "-s" spécifie une taille de pile pour les threads. */

        stack_size = -1;
        while ((opt = getopt(argc, argv, "s:")) != -1) {
            switch (opt) {
            case 's':
                stack_size = strtoul(optarg, NULL, 0);
                break;

            default:
                fprintf(stderr, "Usage : %s [-s stack-size] arg...\n",
                        argv[0]);
                exit(EXIT_FAILURE);
            }
        }

        num_threads = argc - optind;

        /* Initialiser les attributs de création de thread. */

        s = pthread_attr_init(&attr);
        if (s != 0)
            handle_error_en(s, "pthread_attr_init");

        if (stack_size > 0) {
            s = pthread_attr_setstacksize(&attr, stack_size);
            if (s != 0)
                handle_error_en(s, "pthread_attr_setstacksize");
        }

        /* Allouer la mémoire pour les arguments de pthread_create(). */

        tinfo = calloc(num_threads, sizeof(*tinfo));
        if (tinfo == NULL)
            handle_error("calloc");

        /* Créer un thread pour chaque argument en ligne de commande. */

        for (size_t tnum = 0; tnum < num_threads; tnum++) {
            tinfo[tnum].thread_num = tnum + 1;
            tinfo[tnum].argv_string = argv[optind + tnum];

            /* L'appel pthread_create() stocke l'identifiant du thread dans
               l'élément correspondant de tinfo[]. */

            s = pthread_create(&tinfo[tnum].thread_id, &attr,
                               &thread_start, &tinfo[tnum]);
            if (s != 0)
                handle_error_en(s, "pthread_create");
        }

        /* Détruire l'objet des attributs du thread dans la mesure où
           il n'est plus nécessaire. */

        s = pthread_attr_destroy(&attr);
        if (s != 0)
            handle_error_en(s, "pthread_attr_destroy");

        /* Maintenant joindre chaque thread et afficher la valeur qu'il renvoie. */

        for (size_t tnum = 0; tnum < num_threads; tnum++) {
            s = pthread_join(tinfo[tnum].thread_id, &res);
            if (s != 0)
                handle_error_en(s, "pthread_join");

            printf("Thread joint %d ; la valeur renvoyée est %s\n",
                   tinfo[tnum].thread_num, (char *) res);
            free(res);      /* Libérer la mémoire allouée par thread */
        }

        free(tinfo);
        exit(EXIT_SUCCESS);
    }

VOIR AUSSI
getrlimit(2), pthread_attr_init(3), pthread_cancel(3), pthread_detach(3), pthread_equal(3), pthread_exit(3), pthread_getattr_np(3), pthread_join(3), pthread_self(3), pthread_setattr_default_np(3), pthreads(7)

TRADUCTION
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-Pierre Giraud <jean-pierregiraud@neuf.fr>

Cette traduction est une documentation libre ; veuillez vous reporter à la GNU General Public License version 3 (https://www.gnu.org/licenses/gpl-3.0.html) 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.