Cours ‐ Threads - vbridonneau/CoursSysteme GitHub Wiki

Threads

Le concept que nous allons voir ici s'inscrit dans la continuité de ce que nous avons vu avec les processus. Nous allons voir ici les threads qui sont, dans un sens, des processus légers. A la différence des processus que nous avons vu jusqu'à présent, les threads peuvent être vus comme des processus qui partagent leurs mémoires entre eux. Les threads possèdent certains avantages comme un changement de contexte moins coûteux que pour les processus, un découpage des tâches plus faciles, etc. .

Gestion de Threads

Fonction Description
pthread_create Création d'un thread
pthread_exit Sortie d'un thread
pthread_join Attente d'un thread depuis le thread principal
pthread_attr_init Initialisation des attributs d'un thread
pthread_attr_destroy Destruction des attributs d'un thread
pthread_mutex_init Initialisation dynamique d'un mutex
pthread_mutex_destroy Destruction d'un mutex créé par pthread_mutex_init

Notes : La compilation d'un programme utilisant l'une des fonctions de la bibliothèque pthread nécessite de renseigner l'option -pthread à gcc afin de lier la bibliothèque à un programme.

Création d'un thread

La création d'un thread se fait via un appel à la fonction pthread_create dont le prototype est le suivant :

#include <pthread.h>

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

Voyons en détail le rôle de chacun des arguments :

Argumrent Rôle
thread Récupère l'identifiant du thread
attr Sert à paramétrer la création d'un thread
start_routine Fonction que le thread créé devra appeler
arg Argument à passer à la fonction

Plusieurs choses sont à notés ici. Premièrement, lorsque l'on créé un thread, on doit lui récupérer son identifiant pour pouvoir l'attendre à la fin (voir pthread_join plus loin). Ensuite, il est possible de paramétrer la création d'un thread via la variable attr qui peut servir à renseigner si le thread est détaché ou non ou à donner la taille de la pile par exemple. Enfin, et c'est une des différences avec les processus, un thread ne commence pas son exécution à l'endroit où pthread_create est appelée. Un thread commence son exécution en appelant directement la fonction qui lui est passée en paramètre. C'est à cela que sert le paramètre start_routine : c'est un pointeur de fonction qui contient l'adresse de la fonction à appeler. Si on regarde attentivement, la fonction start_routine que l'on passe en paramètre, prend un argument en paramètre. Cet argument est donné via le paramètre arg à la fonction lors de son appel. Si l'on ne souhaite pas en donner, il faut quand même que la fonction que l'on passe en paramètre prenne un argument et on passe à pthread_create NULL. Enfin la fonction start_routine renvoit une valeur sous la forme d'un void* ce qui veut dire que la fonction peut renvoyer un pointeur vers n'importe quelle type. Cette valeur de retour sera passée ensuite récupérer par le thread ayant créé celui appelant pthread_create via la fonction pthread_join.

Notes : souvent, lorsque l'on chereche à créer un thread, on crée une structure dédiée afin d'être moins contraint par le champ arg.

Terminaison d'un thread

Pour sortir d'un thread on utilise la fonction pthread_exit ou on effectue simplement une instruction return à la fin de la fonction que l'on passe à pthread_create. Le prototype de pthread_exit est le suivant :

#include <pthread.h>

void pthread_exit(void *retval);

Cette fonction est appelée pour sortir d'un thread et renvoyer au thread principal une valeur d'un type quelconque via l'argument retval. Pour récuper cette valeur, et de manière générale pour attendre un thread depuis un thread principal, on utilise la fonction pthread_join dont voici le prototype :

#include <pthread.h>

int pthread_join(pthread_t thread, void **retval);

Les deux arguments de cette fonction sont :

  • thread : l'idenfiant du thread que l'on attend.
  • retval : un pointeur vers une variable pour récupérer le résultat passé en argument à pthread_exit. Si on souhaite ignorer cette valeur, il suffit de passer NULL à la fonction.

Cette fonction est l'équivalent de wait avec les processus, les différences étant que l'on doit impérativement préciser quel thread est attendue et que l'on peut récupérer facilement un résultat à la fin de l'exécution d'un thread via le second paramètre de pthread_join.

Attributs d'un thread

Lorsque l'on crée un thred, il est possible que l'on ait des besoins spécifiques. Par exemple, il est possible de vouloir dire que l'on sait à l'avance qu'un thread ne sera pas joignable ou que l'on souhaite plus d'espace pour la pile d'appel. Pour répondre à ce besoin, il est possible de changer les attributs d'un threads via la structure pthread_attr_t. L'implémentation de cette structure dépend du système d'exploitation. Ainsi, pour garantir au mieux la portabilité d'un programme, il est recommandé d'utiliser les fonctions de la famille pthread_attr_* qui permette de mettre à jour cette structure. Parmis elles, on trouve notamment les deux fonctions servant à initialiser et à détruire les attibuts de thread : pthread_attr_init et pthread_attr_destroy respectivement.

⚠️ **GitHub.com Fallback** ⚠️