1. 程式人生 > >SylixOS線程堆棧大小淺析

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

  1. SylixOS線程、線程棧介紹

    SylixOS是多線程操作系統,系統能夠同時創建多個線程,具體最大線程數量取決於系統內存的大小以及編譯SylixOS操作系統時的相關配置,SylixOS線程默認最大線程數量由宏LW_CFG_MAX_THREADS決定,該宏定義可以在文件<config/kernel/kernel_cfg.h>中發現。

  2. 線程的介紹

    線程有時被稱為輕量級進程(Lightweight Process,LWP),在SylixOS中線程又被稱為任務,是某個單一順序的指令流,也是操作系統調度的最小單位,並且每個線程都擁有自己的優先級。一個線程通常由線程句柄(或ID)、當前指令(PC)、CPU寄存器集合、線程棧四個部分組成。

  3. 線程棧的介紹

    每個線程都有自己獨立的棧區,每一個線程控制塊保存了棧區的起始位置、終止位置、以及棧警戒點(用於棧溢出檢查)。當發生任務調度是,線程棧區將保存線程的當前環境(用於上下文恢復)。因此線程棧的設置必須合理,太大將浪費內存空間,太小可能會引起棧溢出。SylixOS中所有的線程都是在同一頁表中,為了滿足實時性要求線程之間沒有地址保護機制,因此棧溢出將可能導致系統崩潰等不可預知的結果。

  4. 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

    獲得線程屬性塊棧填充特性

    ……

    ……

  5. 線程、線程棧相關屬性的設置

    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;

  6. 線程棧大小

    棧大小的設置沒有可以套用的公式,通常根據開發者經驗設置一個較大的值,用存儲空間換取可靠性。在正常進程啟動情況下,會繼承內核線程棧大小。如果創建線程是不設置線程棧屬性,將會繼承內核Shell線程的棧大小。如程序清單 22所示:

    程序清單 22 堆棧大小的函數

    intpthread_attr_setstacksize (pthread_attr_t *pattr, size_tstSize)

    通過shell指令ss可以查看棧的大小,如圖 21所示:

    技術分享

    21 shell指令查看棧大小

  7. 線程堆棧警戒區

    因為我們無法確定所需使用棧區的實際大小,我們通過設置堆棧警戒區的方式來防止堆棧溢出,系統設置默認的警戒區大小為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應用程序開發手冊》

    1. 參考資料

    2. 總結

SylixOS線程堆棧大小淺析