SylixOS線程堆棧大小淺析
目錄
1. SylixOS線程、線程棧介紹 1
1.1 線程的介紹 1
1.2 線程棧的介紹 1
2. SylixOS線程棧大小的分配 1
2.1 線程、線程棧相關屬性的設置 2
2.2 線程棧大小 2
2.3 線程堆棧警戒區 3
3. 總結 5
4. 參考資料 5
SylixOS線程、線程棧介紹
SylixOS是多線程操作系統,系統能夠同時創建多個線程,具體最大線程數量取決於系統內存的大小以及編譯SylixOS操作系統時的相關配置,SylixOS線程默認最大線程數量由宏LW_CFG_MAX_THREADS決定,該宏定義可以在文件<config/kernel/kernel_cfg.h>中發現。
線程的介紹
線程有時被稱為輕量級進程(Lightweight Process,LWP),在SylixOS中線程又被稱為任務,是某個單一順序的指令流,也是操作系統調度的最小單位,並且每個線程都擁有自己的優先級。一個線程通常由線程句柄(或ID)、當前指令(PC)、CPU寄存器集合、線程棧四個部分組成。
線程棧的介紹
每個線程都有自己獨立的棧區,每一個線程控制塊保存了棧區的起始位置、終止位置、以及棧警戒點(用於棧溢出檢查)。當發生任務調度是,線程棧區將保存線程的當前環境(用於上下文恢復)。因此線程棧的設置必須合理,太大將浪費內存空間,太小可能會引起棧溢出。SylixOS中所有的線程都是在同一頁表中,為了滿足實時性要求線程之間沒有地址保護機制,因此棧溢出將可能導致系統崩潰等不可預知的結果。
SylixOS線程棧大小的分配
每一個SylixOS線程都有自己的屬性,主要包括優先級、棧信息、線程參數等。這在線程創建時,SylixOS提供了一個快速獲得系統默認屬性塊的函數Lw_ThreadAttr_GetDefault。該函數返回值是線程屬性塊,默認線程大小為4K(正常通過shell命令運行程序時,程序繼承的是shell的棧)。SylixOS可以使用相關的API函數對線程棧做出相應修改,如表 21所示是一些與線程堆棧相關的API函數。
表 21 線程堆棧相關的API函數
API接口
功能描述
pthread_attr_init
初始化線程屬性塊
pthread_attr_destroy
銷毀一個線程屬性塊
pthread_attr_setstack
設置堆棧的相關參數
pthread_attr_getstack
獲得堆棧的相關參數
pthread_attr_setguardsize
設置一個線程屬性塊的堆棧警戒區大小
pthread_attr_getguardsize
獲取一個線程屬性塊的堆棧警戒區大小
pthread_attr_setstacksize
設置一個線程屬性塊的堆棧大小
pthread_attr_getstacksize
獲取一個線程屬性塊的堆棧大小
pthread_attr_setstackaddr
指定一個線程屬性塊的堆棧地址
pthread_attr_getstackaddr
獲取一個線程屬性塊的堆棧地址
pthread_attr_setstackfilled
設置線程屬性塊棧填充特性
pthread_attr_getstackfilled
獲得線程屬性塊棧填充特性
……
……
線程、線程棧相關屬性的設置
SylixOS提供下面一組函數來對線程的屬性塊參數進行設置,如程序清單 21所示:
程序清單 21 線程屬性塊
/*********************************************************************************************************
線程屬性塊
*********************************************************************************************************/
typedefstruct {
PLW_STACKTHREADATTR_pstkLowAddr; /* 全部堆棧區低內存起始地址 */
size_tTHREADATTR_stGuardSize; /* 堆棧警戒區大小 */
size_tTHREADATTR_stStackByteSize; /* 全部堆棧區大小(字節) */
UINT8THREADATTR_ucPriority; /* 線程優先級 */
ULONGTHREADATTR_ulOption; /* 任務選項 */
PVOIDTHREADATTR_pvArg; /* 線程參數 */
PVOIDTHREADATTR_pvExt; /* 擴展數據段指針 */
} LW_CLASS_THREADATTR;
typedefLW_CLASS_THREADATTR *PLW_CLASS_THREADATTR;
線程棧大小
棧大小的設置沒有可以套用的公式,通常根據開發者經驗設置一個較大的值,用存儲空間換取可靠性。在正常進程啟動情況下,會繼承內核線程棧大小。如果創建線程是不設置線程棧屬性,將會繼承內核Shell線程的棧大小。如程序清單 22所示:
程序清單 22 堆棧大小的函數
intpthread_attr_setstacksize (pthread_attr_t *pattr, size_tstSize)
通過shell指令ss可以查看棧的大小,如圖 21所示:
圖 21 shell指令查看棧大小
線程堆棧警戒區
因為我們無法確定所需使用棧區的實際大小,我們通過設置堆棧警戒區的方式來防止堆棧溢出,系統設置默認的警戒區大小為1k,當出現堆棧溢出的狀況時,系統會預警,如程序清單 23所示:
程序清單 23 堆棧警戒區函數
intpthread_attr_setguardsize (pthread_attr_t *pattr, size_tstGuard)
該函數對線程屬性塊的警戒區大小進行修改,參數stGuard指定新的棧警戒區棧大小。我們通過程序清單 23做一個詳細了解:
程序清單 23 堆棧溢出示例程序
#include<stdio.h>
#include<pthread.h>
#include<time.h>
void *routine(void *arg) {
fprintf(stdout, "pthread running...\n");
while(1);
return (NULL);
}
intmain(intargc, char *argv[]) {
pthread_ttid;
pthread_attr_tattr;
intret;
ret = pthread_attr_init(&attr);
if (ret != 0) {
fprintf(stderr, "pthreadattrinit failed.\n");
return (-1);
}
ret = pthread_create(&tid, &attr, routine, NULL);
if (ret != 0) {
fprintf(stderr, "pthread create failed.\n");
return (-1);
}
pthread_join(tid, NULL);
pthread_attr_destroy(&attr);
return (0);
}
通過shell指令shstack(顯示或者設置shell 任務堆棧大小)設置堆棧大小,再查看是否修改成功,然後運行程序,如圖 22所示線程kl棧溢出:
圖 22 shell任務堆棧大小
再通過ss 查看系統中所有線程與中斷系統堆棧使用情況,如圖 23所示:
圖 23 系統中所有線程與中斷系統堆棧使用情況
我們SylixOS的每個線程都有自己獨立的棧區,對應的線程控制塊保存了該棧區的起始位置、終止位置、以及棧警戒點(用於棧溢出檢查)。在系統提供默認的屬性塊中,棧大小為4k,警戒區大小為1k,用戶也可以根據自己的需求,通過相關的API函數來對棧的大小進行設置。
《SylixOS應用程序開發手冊》
參考資料
總結
SylixOS線程堆棧大小淺析