我是新手,并且在我的带有i686 / 32位架构的Ubuntu 14.04计算机上使用gcc
(版本4.8.2)测试线程本地存储(TLS)类。< / p>
在尝试查明__thread
关键字是否具有所需效果时,我使用gcc test.c
编译此简约测试程序(无错误或警告):
#include <stdio.h>
__thread int i;
int main() {
i = 7;
printf("%d\n",i);
}
并使用工具nm
检查对象代码中符号i
的存储类:
nm a.out | grep ' i'
结果是
00000000 B i
这意味着i
被视为一个共同的全局未初始化变量(存储在BSS部分中)。根据{{1}},线程本地存储变量用字母man nm
表示,而不是L
。
这里有什么问题?
这是B
问题还是真正的问题?
答案 0 :(得分:5)
没有问题,只是nm(1)
写出输出的方式。
nm(1)
的默认输出格式(和信息)在平台之间是不同的(例如,我的Linux桌面中nm(1)
的联机帮助页甚至没有提到L
的线程本地存储)。
但是,如果使用-fs
启用SysV输出格式,则会得到更详细的输出:
$ nm -fs a.out
Symbols from a.out:
Name Value Class Type Size Line Section
...
i |0000000000000000| B | TLS|0000000000000004| |.tbss
...
正如您所看到的,使用此输出格式i
在Type
列下被标识为本地线程,它位于.tbss
。
如果您的发行版的联机帮助页提到了线程本地存储的L
标记,并且您没有以默认输出格式看到它,我会说这是nm(1)
中的错误。< / p>
答案 1 :(得分:3)
您的代码太小了。直到运行时才知道线程数,因此您在可执行文件中看到的变量是main
将使用的变量。创建其他线程时,将分配变量的其他副本。
这是一个演示线程变量的最小程序。
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
__thread int i;
void *foo( void *args )
{
i = 8;
printf( "foo: %d\n", i );
return NULL;
}
int main( void )
{
i = 7;
printf( "main:%d\n", i );
pthread_t pid;
if ( pthread_create( &pid, NULL, foo, NULL ) != 0 )
exit( 1 );
pthread_join( pid, NULL );
printf( "main:%d\n", i );
}