Ответ 1
Недавний GCC, например. GCC 5 поддерживают C11 и его thread_local
(если компилировать, например, gcc -std=c11
). Поскольку комментарий FUZxxl, вы можете использовать (вместо C11 thread_local
) квалификатор __thread
, поддерживаемый более старыми версиями GCC. Читайте о Локальное хранилище потоков.
pthread_getspecific
действительно довольно медленный (он находится в библиотеке POSIX, поэтому не предоставляется GCC, но, например, GNU glibc или musl-libc), поскольку он включает вызов функции. Использование переменных thread_local
, вероятно, будет быстрее.
Посмотрите исходный код файл MUSL thread/pthread_getspecific.c
для примера реализации. Прочитайте этот ответ по соответствующему вопросу.
И _thread
и thread_local
(часто) не магически переведены на вызовы pthread_getspecific
. Обычно они связаны с определенным режимом адреса и/или регистром (подробности специфичны для реализации, связанные с ABI, в Linux я предполагаю, что с x86 -64 имеет больше регистров и режимов адресов, его реализация TLS выполняется быстрее, чем на i386), с помощью compiler, a href= "https://en.wikipedia.org/wiki/Linker_%28computing%29" rel= "nofollow noreferrer" > linker и система времени выполнения. Наоборот, некоторые реализации pthread_getspecific
используют некоторые внутренние переменные thread_local
(в вашей реализации потоков POSIX).
В качестве примера, компиляция следующего кода
#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));
}
с использованием GCC 5.2 (на Debian/Sid) с gcc -m32 -S -O2 -fverbose-asm
приведен следующий код для get_data
с использованием TLS:
.type get_data, @function
get_data:
.LFB3:
.cfi_startproc
movl %gs:[email protected], %eax # data,
ret
.cfi_endproc
и следующий код get_by_key
с явным вызовом 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
Следовательно, использование TLS с __thread
(или thread_local
в C11) должно быть, скорее, быстрее, чем при использовании pthread_getspecific
(избегая накладных расходов на вызов).
Обратите внимание, что thread_local
- это удобный макрос, определенный в <threads.h>
(стандартный заголовок C11).