SylixOS线程堆栈大小浅析

 

1.SylixOS线程、线程栈介绍

    SylixOS是多线程操作系统,系统能够同时创建多个线程,具体最大线程数量取决于系统内存的大小以及编译SylixOS操作系统时的相关配置,SylixOS线程默认最大线程数量由宏LW_CFG_MAX_THREADS决定,该宏定义可以在文件<config/kernel/kernel_cfg.h>中发现。

1.1线程的介绍

    线程有时被称为轻量级进程(Lightweight Process,LWP),在SylixOS中线程又被称为任务,是某个单一顺序的指令流,也是操作系统调度的最小单位,并且每个线程都拥有自己的优先级。一个线程通常由线程句柄(或ID)、当前指令(PC)、CPU寄存器集合、线程栈四个部分组成。

1.2线程栈的介绍

    每个线程都有自己独立的栈区,每一个线程控制块保存了栈区的起始位置、终止位置、以及栈警戒点(用于栈溢出检查)。当发生任务调度是,线程栈区将保存线程的当前环境(用于上下文恢复)。因此线程栈的设置必须合理,太大将浪费内存空间,太小可能会引起栈溢出。SylixOS中所有的线程都是在同一页表中,为了满足实时性要求线程之间没有地址保护机制,因此栈溢出将可能导致系统崩溃等不可预知的结果。

2.SylixOS线程栈大小的分配

    每一个SylixOS线程都有自己的属性,主要包括优先级、栈信息、线程参数等。这在线程创建时,SylixOS提供了一个快速获得系统默认属性块的函数Lw_ThreadAttr_GetDefault。该函数返回值是线程属性块,默认线程大小为4K(正常通过shell命令运行程序时,程序继承的是shell的栈)。SylixOS可以使用相关的API函数对线程栈做出相应修改,如表 2-1所示是一些与线程堆栈相关的API函数。

表 2-1 线程堆栈相关的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

获得线程属性块栈填充特性

……

……

2.1线程、线程栈相关属性的设置

SylixOS提供下面一组函数来对线程的属性块参数进行设置,如程序清单 2-1所示:

程序清单 2-1 线程属性块

/*********************************************************************************************************

线程属性块

*********************************************************************************************************/

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;

2.2线程栈大小

栈大小的设置没有可以套用的公式,通常根据开发者经验设置一个较大的值,用存储空间换取可靠性。在正常进程启动情况下,会继承内核线程栈大小。如果创建线程是不设置线程栈属性,将会继承内核Shell线程的栈大小。如程序清单 2-2所示:

程序清单 2-2 堆栈大小

intpthread_attr_setstacksize (pthread_attr_t *pattr, size_tstSize)

通过shell指令ss可以查看栈的大小,如图 2-1所示:

图 2-1 shell指令查看栈大小

 

2.3线程堆栈警戒区

因为我们无法确定所需使用栈区的实际大小,我们通过设置堆栈警戒区的方式来防止堆栈溢出,系统设置默认的警戒区大小为1k,当出现堆栈溢出的状况时,系统会预警,如程序清单 2-3所示:

程序清单 2-3 堆栈警戒区函数

intpthread_attr_setguardsize (pthread_attr_t *pattr, size_tstGuard)

该函数对线程属性块的警戒区大小进行修改,参数stGuard指定新的栈警戒区栈大小。我们通过程序清单 2-3做一个详细了解:

程序清单 2-3 堆栈溢出示例程序

#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    任务堆栈大小)设置堆栈大小,再查看是否修改成功,然后运行程序,如图 2-2所示线程kl栈溢出:

图 2-2 shell任务堆栈大小

    再通过ss 查看系统中所有线程与中断系统堆栈使用情况,如图 2-3所示:

图 2-3 系统中所有线程与中断系统堆栈使用情况

 

    我们SylixOS的每个线程都有自己独立的栈区,对应的线程控制块保存了该栈区的起始位置、终止位置、以及栈警戒点(用于栈溢出检查)。在系统提供默认的属性块中,栈大小为4k,警戒区大小为1k,用户也可以根据自己的需求,通过相关的API函数来对栈的大小进行设置。

猜你喜欢

转载自my.oschina.net/u/3491369/blog/904213