Cómo imprimir pthread_t

Búsqueda, pero no encuentras 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 una pequeña identificación numérica, identificando en el mensaje de depuración diferentes hilos.

En mi sistema (RHEL 5.3 de 64 bits) se define como unsigned long int, por lo que es un número grande y solo imprimirlo ocupa un lugar valioso en la línea de depuración. ¿Cómo asigna gdb short tids?

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 

Para imprimir solo una ID pequeña para cada pthread_t podría usarse algo como esto (esta vez usando iostreams):

 void printPt(std::ostream &strm, pthread_t pt) { static int nextindex = 0; static std::map ids; if (ids.find(pt) == ids.end()) { ids[pt] = nextindex++; } strm < < ids[pt]; } 

Según la plataforma y la representación real de pthread_t , 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) { ... } 

GDB usa el id-thread (también conocido como kernel pid, aka LWP) para números cortos en Linux. Tratar:

  #include  ... printf("tid = %d\n", syscall(SYS_gettid)); 

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 ítem XBD / TC2 / D6 / 26, agregando pthread_t a la lista de tipos que no requieren ser tipos aritméticos, permitiendo así que pthread_t se defina como una estructura.

Tendrá que buscar en su encabezado sys/types.h y ver cómo se implementa pthread_t ; entonces 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 identificadores de subprocesos cada vez que se inicia un nuevo subproceso :

Para fines de depuración, gdb asocia su propio número de subproceso, siempre un entero único, con cada subproceso de su progtwig.

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

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

  • Cómo obtener identificaciones únicas más cortas para el hilo para el registro.
  • De todos modos, necesitamos imprimir ID pthread_t real para el hilo (solo para enlazar a los valores POSIX al menos).

1. Imprimir identificación POSIX (pthread_t)

Simplemente puede tratar pthread_t como una matriz de bytes con dígitos hexadecimales impresos para cada byte. Entonces no estás limitado por algún tipo de tamaño fijo. El único problema es el orden de bytes. Probablemente te guste si el orden de tus bytes impresos es el mismo que para la impresión simple “int”. Aquí hay un ejemplo para little-endian y solo debería revertirse el orden (¿bajo definir?) Para big-endian:

 #include  #include  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 la ID de hilo real (posix) al índice de alguna tabla. Pero hay 2 enfoques significativamente diferentes:

2.1. Seguimiento de hilos.

Puede rastrear los hilos de ID de todos los hilos existentes en la tabla (sus llamadas pthread_create () deben ser envueltas) y tienen una función de identificación “sobrecargada” que le da solo el índice de la tabla, no la identificación del hilo real. Este esquema también es muy útil para cualquier seguimiento interno de depuración y recursos. La ventaja obvia es el efecto secundario de la instalación de rastreo / depuración a nivel de subprocesos con posible extensión futura. La desventaja es un requisito para rastrear cualquier creación / destrucción de hilos.

Aquí hay un ejemplo parcial de pseudocódigo:

 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. Simplemente registra una nueva identificación de hilo.

Durante el registro, llame a pthread_self () y busque la tabla interna si conoce el hilo. Si se creó el hilo con dicha identificación, su índice se utiliza (o se reutiliza desde el hilo anterior, en realidad no importa, ya que no hay 2 ID iguales para el mismo momento). Si todavía no se conoce el ID del subproceso, se crea una nueva entrada para que se genere / use el nuevo índice.

La ventaja es la simplicidad. La desventaja no es el seguimiento de la creación / destrucción de hilos. Entonces para rastrear esto se requiere una mecánica externa.

En Centos 5.4 x86_64, pthread_t es un typedef a unsigned long.

Por lo tanto, podríamos hacer esto …

 #include  #include  int main() { pthread_t x; printf("%li\n", (unsigned long int) x); std::cout < < (unsigned long int) x << "\n"; } 

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 puede confiar en tener GCC (clang también funciona en este caso), también puede 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 admite esto, 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 thread_id en las llamadas a funciones, pero no funciona, por ejemplo, en Mac OS.

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

Una tabla de búsqueda (pthread_t : int) podría convertirse en una pérdida de memoria en los progtwigs que inician una gran cantidad de subprocesos efímeros.

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

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

Lo sé, este hilo es muy antiguo. Después de haber leído todas las publicaciones anteriores, me gustaría añadir una idea más para manejar esto de una manera ordenada: si entras en el negocio de la asignación de todos modos (mapeando pthread_to a un int), también podrías ir un paso más allá en la legibilidad. Haga su pthread_create_wrapper de tal manera que también tome una cadena … el nombre del hilo. Aprendí a apreciar esta característica de “SetThreadName ()” en Windows y Windows CE. Ventajas: sus identificadores no son solo números, sino que también puede ver cuál de sus hilos tiene su propósito.

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

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

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