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. 总结