3

我是新来的,并且在我的 Ubuntu 14.04 计算机上使用(版本 4.8.2)测试线程本地存储(TLS)类,具有 i686/32 位架构。gcc

在试图找出__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问题还是一个真正的问题?

4

2 回答 2

5

没问题,就是nm(1)写输出的方式。

nm(1)的默认输出格式(和信息)因平台而异(例如nm(1),我的 Linux 桌面中的联机帮助页甚至没有提到L线程本地存储)。

但是,如果使用 启用 SysV 输出格式-fs,则会得到更详细的输出:

$ 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).

于 2015-09-05T17:42:40.483 回答
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 );
}
于 2015-09-05T17:26:20.193 回答