Dans mon destructeur, je veux détruire un fil proprement.
Mon but est d'attendre la fin de l'exécution d'un thread, puis de le détruire.
La seule chose que j'ai trouvée sur l'interrogation de l'état d'un pthread est pthread_attr_setdetachstate mais cela ne vous indique que si votre fil est:
Les deux n'ont rien à voir avec si le thread est toujours en cours d'exécution ou non.
Comment interrogez-vous un pthread pour voir s'il est toujours en cours d'exécution?
On dirait que vous avez deux questions ici:
Réponse: Ceci est directement pris en charge par pthreads - créez votre thread à arrêter arrêté JOINABLE (lors de son premier démarrage) et utilisez pthread_join () pour bloquer votre thread actuel jusqu'à ce que le thread à arrêter ne soit plus fonctionnement.
Réponse: Vous pouvez ajouter un drapeau "thread_complete" pour faire l'affaire:
Scénario: le fil A veut savoir si le fil B est toujours en vie.
Lorsque le thread B est créé, un pointeur sur l'adresse de l'indicateur "thread_complete" lui est attribué. L'indicateur "thread_complete" doit être initialisé à NOT_COMPLETED avant la création du thread. La fonction de point d'entrée du thread B doit immédiatement appeler pthread_cleanup_Push () pour envoyer un "gestionnaire de nettoyage" qui définit l'indicateur "thread_complete" sur COMPLETED.
Voir les détails concernant les gestionnaires de nettoyage ici: pthread gestionnaires de nettoyage
Vous voudrez inclure un appel pthread_cleanup_pop (1) correspondant pour vous assurer que le gestionnaire de nettoyage est appelé quel que soit le cas (c'est-à-dire si le thread se ferme normalement OR en raison d'une annulation, etc.).
Ensuite, le thread A peut simplement vérifier le drapeau "thread_complete" pour voir si le thread B s'est déjà terminé.
NOTE: Votre drapeau "thread_complete" devrait être déclaré "volatile" et devrait être un type atomique - les compilateurs GNU fournissent le sig_atomic_t à cette fin. Cela permet aux deux threads d'accéder de manière cohérente aux mêmes données sans recourir à des constructions de synchronisation (mutexes/sémaphores).
pthread_kill(tid, 0);
Aucun signal n'est envoyé, mais le contrôle des erreurs est toujours effectué afin que vous puissiez l'utiliser pour vérifier l'existence du fichier tid.
CAUTION: Cette réponse est incorrecte. La norme interdit spécifiquement de transmettre l'ID d'un thread dont la durée de vie est terminée. Cet ID peut maintenant spécifier un autre thread ou, pire, il peut faire référence à la mémoire libérée, provoquant un blocage.
Je pense que tout ce dont vous avez besoin est d'appeler pthread_join (). Cet appel ne reviendra pas tant que le fil ne sera pas sorti.
Si vous voulez seulement interroger pour savoir si le thread est toujours en cours d'exécution (et notez que ce n'est généralement pas ce que vous devriez vouloir faire!), Vous pouvez lui demander de définir un booléen volatil sur false juste avant de le quitter. alors votre thread principal pourrait lire le booléen et si c'est toujours vrai, vous savez que le thread est toujours en cours d'exécution. (si elle est fausse, par contre, vous savez que le fil est au moins presque terminé; il est peut-être toujours en train d'exécuter du code de nettoyage après avoir défini la valeur booléenne sur false, donc même dans ce cas, vous devez toujours appeler pthread_join essayant de libérer les ressources auxquelles le fil pourrait avoir accès)
Il n'y a pas de solution entièrement portable, regardez si votre plate-forme supporte pthread_tryjoin_np ou pthread_timedjoin_np. Donc, vous venez de vérifier si le thread peut être rejoint (bien sûr créé avec PTHREAD_CREATE_JOINABLE).
Je pense avoir mis au point une solution qui fonctionne au moins pour Linux. Chaque fois que je crée un fil, je l’ai enregistré, c’est LWP (Light Weight Process ID) et lui attribue un nom unique, par exemple . int lwp = syscall (SYS_gettid); prctl (PR_SET_NAME, (long) "nom unique", 0, 0, 0);
Ensuite, pour vérifier si le fil existe plus tard, ouvrez/proc /pid/ tâche /lwp/ comm et le lis. Si le fichier existe et que son contenu correspond au nom unique que j'ai attribué, le thread existe. Notez que cela ne transmet PAS un TID éventuellement obsolète/réutilisé à une fonction de bibliothèque, donc pas de crash.
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <pthread.h>
#include <sys/prctl.h>
#include <sys/file.h>
#include <stdbool.h>
#include <string.h>
#include <unistd.h>
#include <syscall.h>
pthread_t subthread_tid;
int subthread_lwp;
#define UNIQUE_NAME "unique name"
bool thread_exists (pthread_t thread_id)
{
char path[100];
char thread_name[16];
FILE *fp;
bool thread_exists = false;
// If the /proc/<pid>/task/<lwp>/comm file exists and it's contents match the "unique name" the
// thread exists, and it's the original thread (TID has NOT been reused).
sprintf(path, "/proc/%d/task/%d/comm", getpid(), subthread_lwp);
fp = fopen(path, "r");
if( fp != NULL ) {
fgets(thread_name, 16, fp);
fclose(fp);
// Need to trim off the newline
thread_name[strlen(thread_name)-1] = '\0';
if( strcmp(UNIQUE_NAME, thread_name) == 0 ) {
thread_exists = true;
}
}
if( thread_exists ) {
printf("thread exists\n");
} else {
printf("thread does NOT exist\n");
}
return thread_exists;
}
void *subthread (void *unused)
{
subthread_lwp = syscall(SYS_gettid);
prctl(PR_SET_NAME, (long)UNIQUE_NAME, 0, 0, 0);
sleep(10000);
return NULL;
}
int main (int argc, char *argv[], char *envp[])
{
int error_number;
pthread_create(&subthread_tid, NULL, subthread, NULL);
printf("pthread_create()\n");
sleep(1);
thread_exists(subthread_tid);
pthread_cancel(subthread_tid);
printf("pthread_cancel()\n");
sleep(1);
thread_exists(subthread_tid);
error_number = pthread_join(subthread_tid, NULL);
if( error_number == 0 ) {
printf("pthread_join() successful\n");
} else {
printf("pthread_join() failed, %d\n", error_number);
}
thread_exists(subthread_tid);
exit(0);
}
Permettez-moi de noter la réponse «gagnante», qui comporte un énorme défaut caché et qui, dans certains contextes, peut entraîner des accidents. Sauf si vous utilisez pthread_join, il reviendra encore et encore. Supposons que vous rencontrez un processus et une bibliothèque partagée. Appelez la bibliothèque lib.so.
Permettez-moi de souligner que ce n'est pas un problème hipothetical, j'ai eu le même problème sur notre projet.