Je suis novice en lecture, et j'essaie de le comprendre. J'ai vu des exemples comme celui-ci.
Je pouvais voir que la main()
est bloquée par l'API pthread_exit()
et j'ai vu des exemples où la fonction principale est bloquée par l'API pthread_join()
. Je ne suis pas capable de comprendre quand utiliser quoi?
Je fais référence au site suivant - https://computing.llnl.gov/tutorials/pthreads/ . Je ne parviens pas à comprendre quand utiliser pthread_join()
et quand utiliser pthread_exit()
.
Quelqu'un peut-il s'il vous plaît expliquer? De plus, un bon lien de tutoriel pour les pthreads sera apprécié.
#include <pthread.h>
#include <stdio.h>
#define NUM_THREADS 5
void *PrintHello(void *threadid)
{
long tid;
tid = (long)threadid;
printf("Hello World! It's me, thread #%ld!\n", tid);
pthread_exit(NULL);
}
int main (int argc, char *argv[])
{
pthread_t threads[NUM_THREADS];
int rc;
long t;
for(t=0; t<NUM_THREADS; t++){
printf("In main: creating thread %ld\n", t);
rc = pthread_create(&threads[t], NULL, PrintHello, (void *)t);
if (rc){
printf("ERROR; return code from pthread_create() is %d\n", rc);
exit(-1);
}
}
/* Last thing that main() should do */
pthread_exit(NULL);
Réalisé une dernière chose, c'est-à-dire
pthread_cancel(thread);
pthread_join(thread, NULL);
Parfois, vous souhaitez annuler le thread alors qu'il est en cours d'exécution. Vous pouvez le faire à l'aide de pthread_cancel (thread); . Cependant, n'oubliez pas que vous devez activer le support d'annulation de pthread . code lors de l'annulation.
thread_cleanup_Push(my_thread_cleanup_handler, resources);
pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, 0);
static void my_thread_cleanup_handler(void *arg)
{
// free
// close, fclose
}
Comme expliqué dans les documentations openpub,
pthread_exit()
va quitter le thread qui l'appelle.
Dans votre cas, puisque le principal l’appelle, principal thread se terminera alors que vos threads créés continueront de s’exécuter. Ceci est principalement utilisé dans les cas où le thread principal Est uniquement requis pour générer des threads et les laisser faire leur travail.
pthread_join
suspendra l'exécution du thread qui l'a appelé à moins que le thread cible ne se termine
Ceci est utile dans les cas où vous voulez attendre la fin du/des threads avant de poursuivre le traitement de Dans le thread principal.
pthread_exit
termine le thread appelant pendant que pthread_join
suspend l'exécution du thread appelant jusqu'à ce que les threads cibles aient terminé leur exécution.
Ils sont à peu près bien expliqués en détail dans la documentation du groupe ouvert:
Les deux méthodes garantissent que votre processus ne se termine pas avant la fin de tous vos threads.
La méthode join a votre thread de la fonction main
attendre explicitement tous les threads qui doivent être "joints".
La méthode pthread_exit
termine votre fonction main
et le thread de manière contrôlée. main
a la particularité que mettre fin à main
mettrait fin à l'ensemble de votre processus, y compris à tous les autres threads.
Pour que cela fonctionne, vous devez vous assurer qu'aucun de vos threads n'utilise les variables locales déclarées à l'intérieur de leur fonction main
. L'avantage de cette méthode est que votre main
ne doit pas connaître tous les threads qui ont été démarrés dans votre processus, par exemple parce que d'autres threads ont eux-mêmes créé de nouveaux threads dont main
ne sait rien.
comme on l'a déjà fait remarquer, est utilisé pour la terminaison du thread appelant . Après un appel à cette fonction, un mécanisme de nettoyage compliqué est lancé . Une fois l'opération terminée, le thread est terminé . L'API pthread_exit () est également appelé implicitement quand un appel à la routine return () se produit dans un thread créé par pthread_create () . En fait, un appel à return () et un appel à pthread_exit () ont le même impact, étant appelés à partir d'un Sujet créé par pthread_create ().
Il est très important de distinguer le thread initial, créé implicitement au démarrage de la fonction main (), et les threads créés par pthread_create () . Un appel de la routine return () à partir de la fonction main () appelle implicitement l'exit ( ) appel système et processus complet terminé . Aucun mécanisme de nettoyage de thread n'est démarré . Un appel à pthread_exit () à partir de la fonction main () provoque le démarrage du mécanisme de nettoyage et la fin de son travail, le le fil initial se termine.
Qu'advient-il du processus entier (et des autres threads) lorsque pthread_exit () est appelé à partir de la fonction main () dépend de l'implémentation PTHREAD . Par exemple, lors de l'implémentation IBM OS/400, le processus complet est terminé, y compris d'autres threads, lorsque pthread_exit () est appelé depuis la fonction main () . D'autres systèmes peuvent se comporter différemment . Sur la plupart des machines Linux modernes, l'appel de pthread_exit () à partir du thread initial ne met pas fin au processus complet tant que tous threads terminating . Faites attention en utilisant pthread_exit () de main (), si vous voulez écrire une application portable.
est un moyen pratique d’attendre une fin de thread . Vous pouvez écrire votre propre fonction qui attend une fin de thread, peut-être plus adaptée à votre application, au lieu d’utiliser pthread_join () . Par exemple, cela peut être une fonction basée sur l'attente de variables conditionnelles.
Je recommanderais pour lire un livre de David R. Butenhof “Programmer avec les fils POSIX”. Il explique très bien les sujets abordés (et plus compliqués) (bien que certains détails de la mise en œuvre, tels que l'utilisation de pthread_exit dans la fonction principale, ne soient pas toujours reflétés dans le livre).
Vous n'avez pas besoin d'appels vers pthread_exit(3)
dans votre code particulier.
En général, le thread main
devrait pas appeler pthread_exit
, mais devrait souvent appeler pthread_join(3)
to wait pour qu'un autre thread se termine.
Dans votre fonction PrintHello
, vous n'avez pas besoin d'appeler pthread_exit
car il est implicite après le retour de celui-ci.
Donc, votre code devrait plutôt être:
void *PrintHello(void *threadid) {
long tid = (long)threadid;
printf("Hello World! It's me, thread #%ld!\n", tid);
return threadid;
}
int main (int argc, char *argv[]) {
pthread_t threads[NUM_THREADS];
int rc;
intptr_t t;
// create all the threads
for(t=0; t<NUM_THREADS; t++){
printf("In main: creating thread %ld\n", (long) t);
rc = pthread_create(&threads[t], NULL, PrintHello, (void *)t);
if (rc) { fprintf(stderr, "failed to create thread #%ld - %s\n",
(long)t, strerror(rc));
exit(EXIT_FAILURE);
};
}
pthread_yield(); // useful to give other threads more chance to run
// join all the threads
for(t=0; t<NUM_THREADS; t++){
printf("In main: joining thread #%ld\n", (long) t);
rc = pthread_join(&threads[t], NULL);
if (rc) { fprintf(stderr, "failed to join thread #%ld - %s\n",
(long)t, strerror(rc));
exit(EXIT_FAILURE);
}
}
}
pthread_exit()
mettra fin au thread appelant et en sortira (mais les ressources utilisées par le thread appelant ne seront pas libérées vers le système d'exploitation si elles ne sont pas détachées du thread principal.)
pthrade_join()
attendra ou bloquera le thread appelant jusqu'à ce que le thread cible ne soit pas terminé ..__ Dans Word, il attendra de quitter le thread cible.
Dans votre code, si vous mettez sleep (ou delay) dans la fonction PrintHello
avant pthread_exit()
, le thread principal peut alors quitter et mettre fin au processus complet. Bien que votre fonction PrintHello
ne soit pas terminée, elle se terminera. Si vous utilisez la fonction pthrade_join()
dans main avant d'appeler pthread_exit()
depuis le poste principal, il bloque le thread principal et attend la fin de votre thread appelant (PrintHello
).
Hmm.
POSIX pthread_exit
description from http://pubs.opengroup.org/onlinepubs/009604599/functions/pthread_exit.html :
After a thread has terminated, the result of access to local (auto) variables of the thread is
undefined. Thus, references to local variables of the exiting thread should not be used for
the pthread_exit() value_ptr parameter value.
Ce qui semble aller à l’encontre de l’idée que les variables locales du thread principal () restent accessibles.
L'utilisation de pthread_exit
dans le thread principal (à la place de pthread_join
) laissera le thread principal dans l'état défunt (zombie). N'utilisant pas pthread_join
, les autres threads joignables qui sont terminés resteront également dans l'état zombie et causeront resource leakage.
Si vous ne vous associez pas à un fil pouvant être joint (c’est-à-dire un Non détaché), un "fil de zombie" est créé. Évitez de faire cela, puisque chaque thread zombie consomme des ressources système, et quand suffisant Les fils de zombies se sont accumulés, il ne sera plus possible de créer de nouveaux threads (ou processus).
Un autre point est de garder le thread principal à l'état désactivé, tandis que d'autres threads en cours d'exécution peuvent entraîner des problèmes liés à la mise en œuvre dans diverses conditions, par exemple si des ressources sont allouées dans le thread principal ou si des variables locales au thread principal sont utilisées dans d'autres threads.
En outre, toutes les ressources partagées ne sont libérées que lorsque le processus est terminé, cela ne économise aucune ressource. Donc, je pense que l'utilisation de pthread_exit
à la place de pthread_join
devrait être évitée.