pthread_self pthread_exit example c++ c linux pthreads

c++ - pthread_exit - pthread_self



Cómo imprimir pthread_t (11)

En Centos 5.4 x86_64, pthread_t es un typedef para un largo sin firmar.

Por lo tanto, podríamos hacer esto ...

#include <iostream> #include <pthread.h> int main() { pthread_t x; printf("%li/n", (unsigned long int) x); std::cout << (unsigned long int) x << "/n"; }

Busqué, pero no encontré una respuesta satisfactoria.

Sé que no hay una forma portátil de imprimir un pthread_t.

¿Cómo lo haces en tu aplicación?

Actualizar:

En realidad no necesito pthread_t, sino un pequeño identificador numérico, identificando en los mensajes de depuración diferentes subprocesos.

En mi sistema (RHEL 5.3 de 64 bits) está definido como int largo sin firmar, por lo que es un gran número y solo imprimirlo consume un lugar valioso en la línea de depuración. ¿Cómo gdb asigna tid cortos?


En este caso, depende del sistema operativo, ya que el estándar POSIX ya no requiere que pthread_t sea ​​un tipo aritmético :

IEEE Std 1003.1-2001 / Cor 2-2004, se aplica el elemento XBD / TC2 / D6 / 26, agregando pthread_t a la lista de tipos que no se requiere que sean tipos aritméticos, permitiendo así que pthread_t se defina como una estructura.

Deberá buscar en el encabezado sys/types.h y ver cómo se implementa pthread_t ; Luego puedes imprimirlo como mejor te parezca. Como no hay una forma portátil de hacerlo y no dice qué sistema operativo está utilizando, no hay mucho más que decir.

Editar: para responder a su nueva pregunta, GDB asigna sus propios ID de hilo cada vez que comienza un nuevo hilo :

Para propósitos de depuración, gdb asocia su propio número de hilo, siempre un solo número entero, con cada hilo en su programa.

Si está pensando en imprimir un número único dentro de cada hilo, su opción más limpia probablemente sería decirle a cada hilo qué número usar cuando lo inicie.


GDB usa el ID de hilo (también conocido como kernel pid, también conocido como LWP) para números cortos en Linux. Tratar:

#include <syscall.h> ... printf("tid = %d/n", syscall(SYS_gettid));


Lo sé, este hilo es muy viejo. Después de haber leído todas las publicaciones anteriores, me gustaría agregar una idea más para manejar esto de una manera ordenada: si entras en el negocio de los mapas de todos modos (mapeando pthread_to a un int), también podrías ir un paso más allá en la legibilidad. Haz tu pthread_create_wrapper de modo que también tome una cadena ... el nombre del hilo. Aprendí a apreciar esta característica "SetThreadName ()" en Windows y Windows CE. Ventajas: Sus identificadores no son solo números, sino que también ve, cuál de sus hilos tiene qué propósito.


OK, parece que esta es mi respuesta final. Tenemos 2 problemas reales:

  • Cómo obtener identificadores únicos más cortos para subprocesos para el registro.
  • De todos modos, necesitamos imprimir el ID de pthread_t real para el hilo (solo para vincular a los valores POSIX al menos).

1. Imprimir POSIX ID (pthread_t)

Simplemente puede tratar pthread_t como una matriz de bytes con dígitos hexadecimales impresos para cada byte. Así que no estás limitado por algún tipo de tamaño fijo. El único problema es el orden de bytes. Probablemente le guste que el orden de sus bytes impresos sea el mismo que para el simple "int" impreso. Aquí hay un ejemplo para little-endian y solo se debe revertir el orden (¿debajo de definir?) Para 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. Obtener ID de hilo imprimible más corto

En cualquiera de los casos propuestos, debe traducir el ID de hilo real (posix) al índice de alguna tabla. Pero hay 2 enfoques significativamente diferentes:

2.1. Hilos de pista.

Puede rastrear el ID de subprocesos de todos los subprocesos existentes en la tabla (sus llamadas pthread_create () deben ajustarse) y tener la función de identificación "sobrecargada" que le proporciona solo el índice de la tabla, no el ID del subproceso real. Este esquema también es muy útil para cualquier depuración interna relacionada con la depuración y el seguimiento de recursos. Una ventaja evidente es el efecto secundario de la función de rastreo / depuración a nivel de subproceso con una posible extensión futura. La desventaja es un requisito para rastrear la creación / destrucción de cualquier hilo.

Aquí está el ejemplo de pseudocódigo parcial:

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. Solo registre el nuevo ID de hilo

Durante el registro, llame a pthread_self () y busque la tabla interna si conoce el subproceso. Si se creó un hilo con tal ID, se usa su índice (o se reutilizó de un hilo anterior, en realidad no importa, ya que no hay 2 IDs iguales para el mismo momento). Si aún no se conoce el ID de hilo, se crea una nueva entrada para que se genere / use un nuevo índice.

La ventaja es la simplicidad. Desventaja no es un seguimiento de la creación / destrucción de hilos. Así que para rastrear esto se requiere alguna mecánica externa.


Podrías hacer algo como esto:

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 puedes confiar en tener GCC (el clang también funciona en este caso), también puedes hacer esto:

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 su plataforma lo admite, una opción similar:

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; }

Esto tiene la ventaja de que no tiene que pasar por alto thread_id en llamadas de función, pero no funciona, por ejemplo, en Mac OS.


Puede intentar convertirlo en un corto sin firmar y luego imprimir solo los últimos cuatro dígitos hexadecimales. El valor resultante puede ser lo suficientemente único para sus necesidades.


Solo un suplemento a la primera publicación: use un tipo de unión definido por el usuario para almacenar el pthread_t:

union tid { pthread_t pthread_id; unsigned long converted_id; };

Cuando quiera imprimir pthread_t , cree un tid y asigne tid.pthread_id = ... , luego imprima tid.converted_id .


Una tabla de búsqueda (pthread_t : int) podría convertirse en una pérdida de memoria en programas que inician muchos subprocesos de corta duración.

Crear un hash de los bytes de pthread_t (ya sea estructura o puntero o un entero largo o lo que sea) puede ser una solución utilizable que no requiere tablas de búsqueda. Como con cualquier hash, existe el riesgo de colisiones, pero puede ajustar la longitud del hash para que se adapte a sus necesidades.


si pthread_t es solo un número; Esto sería lo más fácil.

int get_tid(pthread_t tid) { assert_fatal(sizeof(int) >= sizeof(pthread_t)); int * threadid = (int *) (void *) &tid; return *threadid; }


Esto imprimirá una representación hexadecimal de un pthread_t , sin importar lo que realmente sea:

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])); } }

Para imprimir una identificación pequeña para cada pthread_t podría usar algo como esto (esta vez usando 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]; }

Dependiendo de la plataforma y la representación real de pthread_t , aquí podría ser necesario definir un operator< para pthread_t , porque std::map necesita un orden en los elementos:

bool operator<(const pthread_t &left, const pthread_t &right) { ... }