Linux應用程序設計:如何獲取線程棧的使用信息?
面對的問題
對于線程的?臻g,相信各位小伙伴都不陌生。它有下面的這幾項特性:
由操作系統(tǒng)分配固定的空間;
使用一個棧寄存器來保存實時位置;
后進先出。
今天,我們不聊操作系統(tǒng)層面對棧的管理,只從應用程序的角度,來看一下如何實時獲取棧的使用情況。
在一般的單片機/嵌入式程序開發(fā)過程中,在創(chuàng)建一個線程(或者稱作任務)的時候,是可以指定給該線程分配多少?臻g的。
然后在調試的時候呢,周期性的打印出棧區(qū)的使用情況:消耗了多少空間,還剩余多少空間。
這樣的話,跑完每一個測試用例之后,就能得到一個大致的統(tǒng)計數據,從而最終決定:需要給這個線程分配多少棧空間。
例如:在 ucOS 系統(tǒng)中,提供了函數 NT8U OSTaskStkChk(INT8U prio, OS_STK_DATA *p_stk_data),來獲取一個任務的棧使用信息。
但是在 Linux 系統(tǒng)中,并沒有這樣類似的函數,來直接獲取棧使用信息。
因此,為了得到此線程的已使用和空閑?臻g,必須通過其他的方式來獲取。
下面,就提供 2 種解決方案:正規(guī)軍方式和雜牌軍方式!
正規(guī)軍方式
在 Linux 系統(tǒng)中,在創(chuàng)建一個線程的時候,是可以通過線程屬性來設置:為這個線程分配多少的棧(stack)空間的。
如果應用程序不指定的話,操作系統(tǒng)就設置為一個默認的值。
線程創(chuàng)建完畢之后,操作系統(tǒng)在內核空間,記錄了這個線程的一切信息,當然也就包括給它分配的?臻g信息。
為了讓應用層能夠獲取到這個信息,操作系統(tǒng)也提供了相應的系統(tǒng)函數。代碼如下:
pthread_attr_t attr;
void *stack_addr;
int stack_size;
memset(&attr, 0, sizeof(pthread_attr_t));
pthread_getattr_np(pthread_self(), &attr);
pthread_attr_getstack(&attr, &stack_addr, &stack_size);
pthread_attr_destroy(&attr);
printf("statck top = %p ", stack_addr);
printf("stack bottom = %p ", stack_addr + stack_size);
從上面這段代碼中可以看到,它只能獲取?臻g的地址開始以及總的空間大小,仍然不知道當前?臻g的實際使用情況!
我找了一下相關的系統(tǒng)調用,Linux 似乎沒有提供相關的函數。
怎么辦?只能迂回操作。
我們知道,在 Linux x86 平臺上,寄存器 ESP 就是來存儲棧指針的。對于一個滿遞減類型的棧,這個寄存器里的值,就代表了當前棧中最后背使用的、那個?臻g的地址。
因此,只要我們能夠獲取到 ESP 寄存器里的值,就相當于知道了當前這個棧有多少空間被使用了。
那么怎樣來獲取 ESP 寄存器的值呢?既然是寄存器,那就肯定是使用匯編代碼了。
很簡單,就 1 行:
size_t esp_val;
asm("movl %%esp, %0" : "=m"(esp_val) :);
對不起,我錯了!應該是 2 行代碼,忘記變量定義了。
對于匯編代碼不熟悉的小伙伴,可以參考之前總結的一篇文章:內聯匯編很可怕嗎?看完這篇文章,終結它!
找到第 4 個示例,直接抄過來就行。
好了,拿到了以上的所有信息,就可以計算出棧的已使用和空閑空間的大小了:

請輸入評論內容...
請輸入評論/評論長度6~500個字
最新活動更多
-
即日-9.16點擊進入 >> 【限時福利】TE 2025國際物聯網展·深圳站
-
10月23日火熱報名中>> 2025是德科技創(chuàng)新技術峰會
-
10月23日立即報名>> Works With 開發(fā)者大會深圳站
-
10月24日立即參評>> 【評選】維科杯·OFweek 2025(第十屆)物聯網行業(yè)年度評選
-
11月27日立即報名>> 【工程師系列】汽車電子技術在線大會
-
12月18日立即報名>> 【線下會議】OFweek 2025(第十屆)物聯網產業(yè)大會