c multithreading gcc thread-local-storage

¿Cómo funciona gcc `__thread`?



multithreading thread-local-storage (2)

¿Cómo se implementa __thread en gcc? ¿Es simplemente un envoltorio sobre pthread_getspecific y pthread_setspecific ?

Con mi programa que utiliza la API de posix para TLS, estoy un poco decepcionado al ver que el 30% de mi tiempo de ejecución del programa se gasta en pthread_getspecific . Lo llamé en la entrada de cada llamada de función que necesita el recurso. El compilador no parece optimizar pthread_getspecific después de integrar la optimización. Por lo tanto, una vez que las funciones están en línea, el código busca el puntero TLS correcto una y otra vez para obtener el mismo puntero.

¿ __thread ayudará __thread en esta situación? Sé que hay thread_local en C11, pero el gcc que tengo todavía no lo admite. (Pero ahora veo que mi gcc admite _Thread_local no la macro).

Sé que puedo simplemente probarlo y ver. Pero ahora tengo que ir a otro lugar, y me gustaría saber más sobre una característica antes de intentar una reescritura bastante grande.


El __thread de gcc tiene exactamente la misma semántica que _Thread_local de C11. No nos dice para qué plataforma está programando, ya que los detalles de la implementación varían según las plataformas. Por ejemplo, en x86 Linux, gcc debería compilar el acceso a las variables locales de subprocesos como instrucciones de memoria con un prefijo de segmento %fs lugar de invocar pthread_getspecific .


GCC reciente, por ejemplo, GCC 5 es compatible con C11 y su thread_local (si se compila con, por ejemplo, gcc -std=c11 ). Como FUZxxl comentó, usted podría usar (en lugar de C11 thread_local ) el calificador __thread compatible con versiones anteriores de GCC. Lea acerca de Thread Local Storage .

pthread_getspecific es bastante lento (está en la biblioteca POSIX, por lo que no es provisto por GCC sino por ejemplo por GNU glibc o musl-libc ) ya que involucra una llamada a la función. El uso de variables thread_local probablemente será más rápido.

Busque en el código fuente del archivo thread/pthread_getspecific.c de MUSL para ver un ejemplo de implementación. Lea esta respuesta a una pregunta relacionada.

Y _thread & thread_local (a menudo) no se traducen mágicamente a llamadas a pthread_getspecific . Por lo general, involucran algún modo de dirección y / o registro específico (los detalles son específicos de la implementación, relacionados con ABI ; en Linux, supongo que como x86-64 tiene más registros y modos de dirección, su implementación de TLS es más rápida que en i386), con la ayuda del compiler , el linker y el sistema de ejecución . Podría suceder, por el contrario, que algunas implementaciones de pthread_getspecific están usando algunas variables internas thread_local (en su implementación de subprocesos POSIX).

Como ejemplo, compilando el siguiente código

#include <pthread.h> const extern pthread_key_t key; __thread int data; int get_data (void) { return data; } int get_by_key (void) { return *(int*) (pthread_getspecific (key)); }

usando GCC 5.2 (en Debian / Sid) con gcc -m32 -S -O2 -fverbose-asm da el siguiente código para get_data usando TLS:

.type get_data, @function get_data: .LFB3: .cfi_startproc movl %gs:data@ntpoff, %eax # data, ret .cfi_endproc

y el siguiente código de get_by_key con una llamada explícita a pthread_getspecific :

get_by_key: .LFB4: .cfi_startproc subl $24, %esp #, .cfi_def_cfa_offset 28 pushl key # key .cfi_def_cfa_offset 32 call pthread_getspecific # movl (%eax), %eax # MEM[(int *)_4], MEM[(int *)_4] addl $28, %esp #, .cfi_def_cfa_offset 4 ret .cfi_endproc

Por lo tanto, el uso de TLS con __thread (o thread_local en C11) probablemente debería ser más rápido que usar pthread_getspecific (evitando la sobrecarga de una llamada).

Observe que thread_local es una macro de conveniencia definida en <threads.h> (un encabezado estándar de C11).