目录
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应用程序开发手册》
-
参考资料
-
总结
-