2012-01-04 161 views
2

我想通過一些函數來獲取線程的堆棧地址,我們可以通過pthread_self()。可能嗎?我這樣做的原因是因爲我想爲自己的堆棧中的某個線程寫一個自己分配的線程標識符。我可以在堆棧末尾(堆棧內存的末尾,而不是當前的堆棧地址)寫入數據,因此我們可以期望應用程序不會到達堆棧的底部,因此可以使用空間。我可以從pthread_self()獲得一個線程的堆棧地址()

換句話說,我想使用線程堆棧來放置一種線程局部變量。那麼,我們是否有像pthread提供的以下功能?

stack_address = stack_address_for_thread(pthread_self()); 

我可以使用gcc的線程局部變量的語法來達到這個目的,但我處於無法使用它們的狀態。

+1

你會如何使用這樣的地址?在C語言中,「堆棧」的地址不是很好定義,因爲語言本身不需要使用堆棧。即使您知道架構使用堆棧,線程的當前幀將隨着線程調用並返回函數而一直改變。 – unwind 2012-01-04 15:35:21

+0

uwind,我同意,但是就像我說過的,我可以將我的變量放置在棧底的某處。到最後,我的意思是分配堆棧的結束。所以,如果我們有1 MB的堆棧,我可以把它放下1MB。我知道它的駭人聽聞,但我們可以預料,一個應用程序不太可能陷入堆棧底部,並且幾個字節將永遠保持空閒狀態。 – MetallicPriest 2012-01-04 15:38:42

+0

@MetallicPriest:儘管如此,爲什麼?我喜歡這個問題,但仍然奇怪爲什麼你不能將數據存儲在更容易訪問(更安全)的地方。 – 2012-01-04 15:41:01

回答

-2

首先得到堆棧的底部,並給它的讀/寫權限以下面的代碼。

pthread_attr_t attr; 
void * stackaddr; 
int * plocal_var; 
size_t stacksize; 

pthread_getattr_np(pthread_self(), &attr); 
pthread_attr_getstack(&attr, &stackaddr, &stacksize); 

printf("stackaddr = %p, stacksize = %d\n", stackaddr, stacksize); 

plocal_var = (int*)mmap(stackaddr, 4096, PROT_READ | PROT_WRITE, 
      MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED, -1, 0); 
// Now try to write something 
*plocal_var = 4; 

,然後你可以得到線程ID,與功能get_thread_id(如下圖所示)。請注意,調用大小爲4096的mmap會將棧的邊界壓入4096,這就是爲什麼我們在獲取局部變量地址時減去4096的原因。

int get_thread_id() 
{ 
    pthread_attr_t attr; 
    char * stackaddr; 
    int * plocal_var; 
    size_t stacksize; 

    pthread_getattr_np(pthread_self(), &attr); 
    pthread_attr_getstack(&attr, (void**)&stackaddr, &stacksize); 

    //printf("stackaddr = %p, stacksize = %d\n", stackaddr, stacksize); 

    plocal_var = (int*)(stackaddr - 4096); 

    return *plocal_var; 
} 
+1

如果你不能使用線程本地化,那你認爲'pthread_getattr_np' * *會起作用嗎? – 2012-01-04 15:59:10

+0

這真的很不好,而且會依賴於你的堆棧的特定數據佈局。在標準和工具中提供了線程專用存儲的方法,使用它們。 – 2012-01-04 16:32:55

+1

通過使用MAP_FIXED,您可以運行發生映射的任何事情的重大風險。充其量,這是一個不完美的解決方案。 – 2012-01-04 18:05:42

6

可能最好使用pthread_key_createpthread_key_getspecific,讓實施擔心這些細節。

使用的一個很好的例子是在這裏:

pthread_key_create

編輯:我要澄清 - 我建議你使用創建線程本地信息的libpthread提供的方法,而不是滾動您自己把東西推到堆棧的盡頭,可能會丟失信息。

2

隨着GCC,它是簡單的聲明你的線程局部變量與__thread關鍵字,像

__thread int i; 
    extern __thread struct state s; 
    static __thread char *p; 

也就是說GCC具體的(但我會猜clang有它也,和最新的C++ &未來的C標準具有比基於指針黑客類似的東西),但不脆upeon pthread_self()(應該是有點快,但移植性較差,比pthread_key_getsspecific,爲suggested by Denniston

但我真的很喜歡你給更多的背景和motivat在你的問題離子。

+0

是的Basile,我知道如何在gcc中創建線程局部變量,但正如我在我的問題中所說的,我不能在這裏使用它們。 – MetallicPriest 2012-01-04 15:52:28

+0

你應該解釋爲什麼你不能使用它們。你應該解釋爲什麼你的解決方案更好(我不這麼認爲)。 – 2012-01-04 15:54:23

+1

線程本地存儲'_Thread_local'也是C11附帶的一個新特性,它實際上等同於這個gcc擴展。所以在gcc中使用這個特性是未來的證明。 – 2012-01-04 16:29:48

2

我想寫我自己的分配線程標識的線程

有多種方式來實現這一目標。最明顯的一個:

__thread int my_id; 

我可以通過gcc的使用線程局部變量的語法用於此目的,但我的情況,我可以不使用它們。

你需要說明的是爲什麼你不能使用線程本地。其他解決方案(如pthread_getattr_np)也無法正常工作的可能性很高。

相關問題