gcc:编译为 BSS 的线程局部变量
gcc: Thread-local variable compiled as BSS
我是新手,正在测试 线程本地存储 (TLS) class gcc
(版本 4.8.2)在我的 Ubuntu 具有 i686/32 位架构的 14.04 计算机。
为了找出 __thread
关键字是否具有预期的效果,我用 gcc test.c
编译了这个简约的测试程序(没有错误或警告):
#include <stdio.h>
__thread int i;
int main() {
i = 7;
printf("%d\n",i);
}
并使用工具nm
查看目标代码中符号i
的存储class:
nm a.out | grep ' i'
结果是
00000000 B i
这意味着i
被当作一个公共的全局未初始化变量(存储在BSS部分)。根据 man nm
,线程本地存储变量由字母 L
表示,而不是 B
.
这是怎么回事?
这是nm
问题还是真正的问题?
您的代码太少了。直到运行时才知道线程数,因此您在可执行文件中看到的变量就是 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 );
}
没问题,就是nm(1)
写输出的方式。
nm(1)
的默认输出格式(和信息)在平台之间是不同的(例如 nm(1)
在我的 Linux 桌面上的联机帮助页甚至没有提到 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)
中的错误.
我是新手,正在测试 线程本地存储 (TLS) class gcc
(版本 4.8.2)在我的 Ubuntu 具有 i686/32 位架构的 14.04 计算机。
为了找出 __thread
关键字是否具有预期的效果,我用 gcc test.c
编译了这个简约的测试程序(没有错误或警告):
#include <stdio.h>
__thread int i;
int main() {
i = 7;
printf("%d\n",i);
}
并使用工具nm
查看目标代码中符号i
的存储class:
nm a.out | grep ' i'
结果是
00000000 B i
这意味着i
被当作一个公共的全局未初始化变量(存储在BSS部分)。根据 man nm
,线程本地存储变量由字母 L
表示,而不是 B
.
这是怎么回事?
这是nm
问题还是真正的问题?
您的代码太少了。直到运行时才知道线程数,因此您在可执行文件中看到的变量就是 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 );
}
没问题,就是nm(1)
写输出的方式。
nm(1)
的默认输出格式(和信息)在平台之间是不同的(例如 nm(1)
在我的 Linux 桌面上的联机帮助页甚至没有提到 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)
中的错误.