Des lecteurs comme vous aident à soutenir MUO. Lorsque vous effectuez un achat en utilisant des liens sur notre site, nous pouvons gagner une commission d'affiliation. En savoir plus.

Sous Linux, vous pouvez créer et gérer des threads en C/C++ à l'aide de la bibliothèque de threads POSIX (pthread). Contrairement à d'autres systèmes d'exploitation, il y a peu de différence entre un thread et un processus sous Linux. C'est pourquoi Linux fait souvent référence à ses threads comme des processus légers.

En utilisant la bibliothèque pthread, vous pouvez créer des threads, attendre qu'ils se terminent et les terminer explicitement.

L'historique de l'utilisation des threads sous Linux

Avant la version 2.6 de Linux, l'implémentation principale du thread était LinuxThreads. Cette implémentation présentait des limites importantes en termes de performances et d'opérations de synchronisation. Une limite sur le nombre maximum de threads pouvant s'exécuter les a limités à des milliers.

En 2003, une équipe dirigée par des développeurs d'IBM et de RedHat a réussi à rendre le

Bibliothèque de threads POSIX native (NPTL) projet disponible. Il a été introduit pour la première fois dans RedHat Enterprise version 3 pour résoudre les problèmes de performances avec la machine virtuelle Java sous Linux. Aujourd'hui, la bibliothèque GNU C contient des implémentations des deux mécanismes de threading.

Aucun de ceux-ci n'est une implémentation de threads verts, qu'une machine virtuelle gérerait et exécuterait en mode purement utilisateur. Lorsque vous utilisez la bibliothèque pthread, le noyau crée un thread à chaque démarrage d'un programme.

Vous pouvez trouver des informations spécifiques aux threads pour tout processus en cours d'exécution dans les fichiers sous /proc//task. Il s'agit de l'emplacement standard pour les informations de processus sous la norme procfs Linux. Pour les applications à thread unique, il apparaîtra qu'il existe un enregistrement de tâche avec la même valeur que le PID sous ce répertoire.

Logique de travail des threads

Les threads sont comme des processus en cours d'exécution sur le système d'exploitation. Dans les systèmes à processeur unique (par exemple, les microcontrôleurs), le noyau du système d'exploitation simule les threads. Cela permet aux transactions de s'exécuter simultanément via le découpage.

Un système d'exploitation monocœur ne peut réellement exécuter qu'un seul processus à la fois. Cependant, dans systèmes multicœurs ou multiprocesseurs, ces processus peuvent s'exécuter simultanément.

Création de threads en C

Vous pouvez utiliser le pthread_create fonction pour créer un nouveau fil. Le pthread.h Le fichier d'en-tête inclut sa définition de signature ainsi que d'autres fonctions liées au thread. Les threads utilisent le même espace d'adressage et les mêmes descripteurs de fichiers que le programme principal.

La bibliothèque pthread inclut également le support nécessaire pour les opérations mutex et conditionnelles requises pour les opérations de synchronisation.

Lorsque vous utilisez les fonctions de la bibliothèque pthread, vous devez vous assurer que le compilateur lie le pthread bibliothèque dans votre exécutable. Si nécessaire, vous pouvez demander au compilateur de créer un lien vers la bibliothèque à l'aide de la commande -l option:

gcc-o test test_thread.c -lpthread

La fonction pthread_create a la signature suivante :

entierpthread_create(pthread_t *fil de discussion, constantepthread_attr_t *attr, annuler *(*démarrer_routine)(annuler *), annuler *arg)

Elle renvoie 0 si la procédure a réussi. En cas de problème, il renvoie un code d'erreur non nul. Dans la signature de fonction ci-dessus :

  • Le fil le paramètre est de type pthread_t. Le fil créé sera toujours accessible avec cette référence.
  • Le attribut Le paramètre vous permet de spécifier un comportement personnalisé. Vous pouvez utiliser une série de fonctions spécifiques aux threads commençant par pthread_attr_ pour configurer cette valeur. Les personnalisations possibles sont la stratégie de planification, la taille de la pile et la stratégie de détachement.
  • start_routine spécifie la fonction que le thread exécutera.
  • argument représente une structure de données générique transmise à la fonction par le thread.

Voici un exemple d'application :

#inclure
#inclure
#inclure
#inclure

annuler *ouvrier(annuler *données)
{
carboniser *nom = (carboniser*)données;

pour (entier je = 0; je < 120; je++)
{
tu dors(50000);
printf("Bonjour du fil nom = %s\n", nom);
}

printf("Thread %s terminé !\n", nom) ;
retourNUL;
}

entierprincipal(annuler)
{
pthread_t th1, th2;
pthread_create(&th1, NUL, travailleur, "X");
pthread_create(&th2, NUL, travailleur, "Y");
dormir(5);
printf("Quitter le programme principal\n");
retour0;
}

Types de filetage

Lorsqu'un thread revient du principal() fonction dans une application, tous les threads se terminent et le système libère toutes les ressources utilisées par le programme. De même, lorsque vous quittez un thread avec une commande telle qu'un sortie(), votre programme terminera tous les threads.

Avec le pthread_join fonction, vous pouvez attendre qu'un thread se termine à la place. Le thread utilisant cette fonction se bloquera jusqu'à ce que le thread attendu se termine. Les ressources qu'ils utilisent à partir du système ne sont pas restituées même dans des cas tels que l'arrêt de threads joignables, non planifié par le processeur, ou même l'échec de la jointure avec ptread_join.

Parfois, il y a des situations où joindre avec pthread_join n'a pas de sens; s'il est impossible de prédire quand le fil se terminera, par exemple. Dans ce cas, vous pouvez vous assurer que le système renvoie automatiquement toutes les ressources au point où le thread revient.

Pour ce faire, vous devez démarrer les discussions pertinentes avec le DÉTACHÉ statut. Au démarrage d'un fil, DÉTACHER le statut peut être défini via des valeurs d'attribut de thread ou avec le pthread_detach fonction:

entierpthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
entierpthread_detach(pthread_t fil de discussion);

Voici un exemple d'utilisation de pthread_join(). Remplacez la fonction principale du premier programme par la suivante :

entierprincipal(annuler)
{
pthread_t th1, th2;
pthread_create(&th1, NUL, travailleur, "X");
pthread_create(&th2, NUL, travailleur, "Y");
dormir(5);
printf("sortie du programme principal\n");
pthread_join (th1, NUL);
pthread_join (th2, NUL);
retour0;
}

Lorsque vous compilez et exécutez le programme, votre sortie sera :

Salut du fil Y
Salut du fil X
Salut du fil Y
...
Salut du fil Y
sortie du programme principal
Salut du fil X
...
Salut du fil X
Sujet X terminé !
Salut du fil Y
Fil Y terminé !

Terminaison de fil

Vous pouvez annuler un thread avec un appel à pthread_cancel, en passant le correspondant pthread_t identifiant:

entierpthread_cancel(pthread_t fil de discussion);

Vous pouvez voir cela en action dans le code suivant. Encore une fois, seul le principal la fonction est différente :

entierprincipal(annuler)
{
pthread_t th1, th2;
pthread_create(&th1, NUL, travailleur, "X");
pthread_create(&th2, NUL, travailleur, "Y");
dormir(1);
printf("> Annulation du fil Y!!\n");
pthread_cancel (th2);
tu dors(100000);
printf("> Annulation du fil X !\n" );
pthread_cancel (th1);
printf("sortie du programme principal\n");
retour0;
}

Pourquoi les fils de discussion sont-ils créés ?

Les systèmes d'exploitation essaient toujours d'exécuter des threads sur un ou plusieurs processeurs, soit à partir d'une liste créée par l'utilisateur, soit à partir d'une liste de threads créée par l'utilisateur. Certains threads ne peuvent pas s'exécuter car ils attendent un signal d'entrée/sortie du matériel. Ils peuvent également attendre volontairement, attendre une réponse d'un autre thread ou être bloqués par un autre thread.

Vous pouvez ajuster les ressources que vous allouez aux threads que vous créez à l'aide de pthread. Il peut s'agir d'une politique de planification personnalisée ou vous pouvez choisir des algorithmes de planification tels que FIFO ou Round-robin si vous le souhaitez.