2015-09-05 58 views
3

我是新手,并在我的Ubuntu 14.04计算机上使用i686/32位体系结构测试线程本地存储(TLS)类,gcc(4.8.2版)。gcc:线程局部变量编译为BSS

在试图找出__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部分)。根据man nm,线程本地存储变量用字母L表示,而不是B

这里有什么问题?

这是一个nm问题或一个真正的问题?

回答

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)中的错误。

+1

就是这样。感谢您的解释,确实我得到了相同的输出。至于手册页,我在网上的一个UNIX手册页上没有意识到。 – rplantiko

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); 
} 
+0

感谢您使用这个代码框架,它实际上对我写的_real_程序有帮助!但对于这个问题,我的问题更多的是理解nm的输出,所以FilipeGonçalves得到了答案(他向我展示了如何使用nm -fs来检查存储类)。 – rplantiko