2015-09-05 61 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