gcc:编译为BSS的线程局部变量

时间:2015-09-05 17:07:52

标签: c multithreading gcc nm

我是新手,并且在我的带有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问题还是真正的问题?

2 个答案:

答案 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
...

正如您所看到的,使用此输出格式iType列下被标识为本地线程,它位于.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 );
}