Recherche, mais ne trouve pas de réponse satisfaisante.
Je sais qu’il n’existe pas de moyen portable d’imprimer un pthread_t.
Comment faites-vous dans votre application?
Mettre à jour:
En fait, je n'ai pas besoin de pthread_t, mais d'un petit identifiant numérique, identifiant dans le message de débogage différents threads.
Sur mon système (RHEL 5.3 64 bits), il est défini comme unsigned long int, il est donc gros et son impression occupe un emplacement précieux dans la ligne de débogage. Comment gdb attribue short tids?
Cela affichera une représentation hexadécimale d'un pthread_t
, peu importe ce que c'est réellement:
void fprintPt(FILE *f, pthread_t pt) {
unsigned char *ptc = (unsigned char*)(void*)(&pt);
fprintf(f, "0x");
for (size_t i=0; i<sizeof(pt); i++) {
fprintf(f, "%02x", (unsigned)(ptc[i]));
}
}
Pour simplement imprimer un petit identifiant pour chaque pthread_t
, quelque chose comme ceci pourrait être utilisé (cette fois en utilisant iostreams):
void printPt(std::ostream &strm, pthread_t pt) {
static int nextindex = 0;
static std::map<pthread_t, int> ids;
if (ids.find(pt) == ids.end()) {
ids[pt] = nextindex++;
}
strm << ids[pt];
}
En fonction de la plate-forme et de la représentation réelle de pthread_t
, il peut être nécessaire ici de définir un operator<
pour pthread_t
, car std::map
nécessite un classement des éléments:
bool operator<(const pthread_t &left, const pthread_t &right) {
...
}
GDB utilise le thread-id (alias kernel pid, alias LWP) pour les nombres courts sous Linux. Essayer:
#include <syscall.h>
...
printf("tid = %d\n", syscall(SYS_gettid));
Dans ce cas, cela dépend du système d'exploitation, car la norme POSIX n'exige plus que pthread_t
soit un type arithmétique :
La norme IEEE 1003.1-2001/Cor 2-2004, élément XBD/TC2/D6/26 est appliquée, en ajoutant
pthread_t
à la liste des types qui ne doivent pas obligatoirement être des types arithmétiques, ce qui permet de définirpthread_t
comme structure.
Vous devrez regarder dans votre en-tête sys/types.h
et voir comment pthread_t
est implémenté; alors vous pouvez l'imprimer comme bon vous semble. Comme il n'y a pas de moyen portable de le faire et que vous ne dites pas quel système d'exploitation vous utilisez, il n'y a pas beaucoup plus à dire.
Edit: pour répondre à votre nouvelle question, GDB attribue ses propres identifiants de thread à chaque démarrage d'un nouveau thread :
À des fins de débogage, gdb associe son propre numéro de thread (toujours un entier) à chaque thread de votre programme.
Si vous souhaitez imprimer un numéro unique à l'intérieur de chaque fil, votre solution la plus propre serait probablement d'indiquer à chaque fil le numéro à utiliser pour le démarrer.
OK, cela semble être ma réponse finale. Nous avons 2 problèmes réels:
1. Imprimer l'ID POSIX (pthread_t)
Vous pouvez simplement traiter pthread_t comme un tableau d'octets avec des chiffres hexadécimaux imprimés pour chaque octet. Donc, vous n'êtes pas limité par un type de taille fixe. Le seul problème est l'ordre des octets. Vous aimez probablement si l'ordre de vos octets imprimés est le même que pour un simple "int" imprimé. Voici un exemple pour le little-endian et seul l’ordre devrait être inversé (pour définir?) Pour le big-endian:
#include <pthread.h>
#include <stdio.h>
void print_thread_id(pthread_t id)
{
size_t i;
for (i = sizeof(i); i; --i)
printf("%02x", *(((unsigned char*) &id) + i - 1));
}
int main()
{
pthread_t id = pthread_self();
printf("%08x\n", id);
print_thread_id(id);
return 0;
}
2. Obtenez un ID de fil imprimable plus court
Dans tous les cas proposés, vous devez traduire l'ID de thread réel (posix) en index d'une table. Mais il existe 2 approches très différentes:
2.1. Suivre les discussions.
Vous pouvez suivre l'ID de tous les threads existants dans la table (leurs appels pthread_create () doivent être encapsulés) et disposer d'une fonction id "surchargée" qui vous permet d'obtenir uniquement l'index de table, et non le véritable ID de thread. Ce schéma est également très utile pour tout débogage interne lié au thread et le suivi des ressources. Un avantage évident est l’effet secondaire de la fonction de traçage/débogage au niveau des threads avec une extension future possible. L’inconvénient est la nécessité de suivre toute création/destruction de threads.
Voici un exemple de pseudocode partiel:
pthread_create_wrapper(...)
{
id = pthread_create(...)
add_thread(id);
}
pthread_destruction_wrapper()
{
/* Main problem is it should be called.
pthread_cleanup_*() calls are possible solution. */
remove_thread(pthread_self());
}
unsigned thread_id(pthread_t known_pthread_id)
{
return seatch_thread_index(known_pthread_id);
}
/* user code */
printf("04x", thread_id(pthread_self()));
2.2. Enregistrez simplement un nouvel identifiant de fil.
Pendant la journalisation, appelez pthread_self () et recherchez dans la table interne s’il connaît le thread . Si un thread avec un tel ID a été créé, son index est utilisé (ou réutilisé à partir d’un thread précédent, en réalité, il n’a pas ID pour le même moment). Si l'ID de thread n'est pas encore connu, une nouvelle entrée est créée afin qu'un nouvel index soit généré/utilisé.
L'avantage est la simplicité. L’inconvénient n’est pas le suivi de la création/destruction de threads. Donc, pour suivre cela, certains mécanismes externes sont nécessaires.
Sur Centos 5.4 x86_64, pthread_t est une définition de type pour un signe long.
Par conséquent, nous pourrions faire ceci ...
#include <iostream>
#include <pthread.h>
int main() {
pthread_t x;
printf("%li\n", (unsigned long int) x);
std::cout << (unsigned long int) x << "\n";
}
Vous pouvez faire quelque chose comme ça:
int thread_counter = 0;
pthread_mutex_t thread_counter_lock = PTHREAD_MUTEX_INITIALIZER;
int new_thread_id() {
int rv;
pthread_mutex_lock(&thread_counter_lock);
rv = ++thread_counter;
pthread_mutex_unlock(&thread_counter_lock);
return rv;
}
static void *threadproc(void *data) {
int thread_id = new_thread_id();
printf("Thread %d reporting for duty!\n", thread_id);
return NULL;
}
Si vous pouvez compter sur GCC (clang fonctionne également dans ce cas), vous pouvez également le faire:
int thread_counter = 0;
static void *threadproc(void *data) {
int thread_id = __sync_add_and_fetch(&thread_counter, 1);
printf("Thread %d reporting for duty!\n", thread_id);
return NULL;
}
Si votre plateforme le supporte, une option similaire:
int thread_counter = 0;
int __thread thread_id = 0;
static void *threadproc(void *data) {
thread_id = __sync_add_and_fetch(&thread_counter, 1);
printf("Thread %d reporting for duty!\n", thread_id);
return NULL;
}
Cela présente l’avantage de ne pas avoir à passer thread_id dans les appels de fonction, mais cela ne fonctionne pas, par exemple. sur Mac OS.
si pthread_t est juste un nombre; ce serait le plus facile.
int get_tid(pthread_t tid)
{
assert_fatal(sizeof(int) >= sizeof(pthread_t));
int * threadid = (int *) (void *) &tid;
return *threadid;
}
Une table de consultation (pthread_t : int)
pourrait devenir une fuite de mémoire dans les programmes qui lancent beaucoup de threads de courte durée.
La création d'un hachage des octets du pthread_t
(structure, pointeur ou entier long, etc.) peut constituer une solution utilisable ne nécessitant pas de table de consultation. Comme pour tout hash, il y a un risque de collision, mais vous pouvez ajuster la longueur du hash pour répondre à vos besoins.
Je sais, ce fil est très vieux. Après avoir lu tous les articles ci-dessus, je voudrais ajouter une idée supplémentaire pour gérer cela de façon élégante: lisibilité. Faites en sorte que votre pthread_create_wrapper prenne une chaîne aussi ... le nom du thread. J'ai appris à apprécier cette fonctionnalité "SetThreadName ()" sur Windows et Windows CE. Avantages: vos identifiants ne sont pas que des chiffres, mais vous voyez également lequel de vos fils a quel but.
Vous pouvez essayer de le convertir en un raccourci non signé, puis d’imprimer uniquement les quatre derniers chiffres hexadécimaux. La valeur résultante pourrait être assez unique pour vos besoins.
Juste un supplément au premier message: utilisez un type d'union défini par l'utilisateur pour stocker le pthread_t:
union tid {
pthread_t pthread_id;
unsigned long converted_id;
};
Chaque fois que vous souhaitez imprimer pthread_t
, créez une tid
et assignez tid.pthread_id = ...
, puis imprimez tid.converted_id
.