SylixOS线程私有数据浅析
2017-05-19 14:15
148 查看
目录
1.
线程私有数据概述 1
2.
线程私有数据的相关API函数流程浅析 1
2.1 加入线程私有变量 1
2.2 删除线程私有变量 3
2.3 设置私有线程变量 6
2.4 获得线程私有变量值 8
3.
总结 10
4.
参考文献 10
图 2-1
加入线程私有变量
程序清单 2-1
加入线程私有变量输入
程序清单 2-2
判断是否在中断
检查线
在进入内核态之前,检查当前线程ID是否符合线程规范,以判断该线程是否有效。具体实现如程序清单 2-3所示。
程序清单 2-3
检查线程有效性
程序清单 2-4
检查线程有效性
程序清单 2-5
分配控制块
程序清单 2-6
检查控制块的有效性
程序清单 2-7
链接控制块
图 2-2
删除线程私有变量
程序清单 2-8
删除线程私有数据输入
程序清单 2-9
查找控制块并解链
图 2-3
设置线程私有变量
程序清单 2-10
设置线程私有变量的值输入
程序清单 2-11
查找控制块并判断是否为当前线程
图 2-4
获得线程私有变量值
程序清单 2-12
私有线程变量值获取
程序清单 2-13
查找控制块并判断是否为当前线程
2. SylixOS源码
1.
线程私有数据概述 1
2.
线程私有数据的相关API函数流程浅析 1
2.1 加入线程私有变量 1
2.2 删除线程私有变量 3
2.3 设置私有线程变量 6
2.4 获得线程私有变量值 8
3.
总结 10
4.
参考文献 10
线程私有数据概述
在SylixOS中为了满足多线程安全的要求,使得一种资源可以安全的被多个线程使用,采用了包括代码临界区保护和可重入性等方法。本文描述实现可重入的一种方法:线程私有数据。值得注意的是这种保护方式牺牲了系统的实时性并且只针对单CPU系统有效,若非必要,SylixOS不推荐使用此方式。线程私有数据的相关API函数流程浅析
加入线程私有变量
加入线程私有变量的流程如图 2-1所示。图 2-1
加入线程私有变量
输入
在调用API_ThreadVarAdd函数时,我们需要输入线程ID以及私有变量地址。具体实现如程序清单 2-1所示。程序清单 2-1
加入线程私有变量输入
ULONGAPI_ThreadVarAdd (LW_OBJECT_HANDLEulId, ULONG *pulAddr) { REGISTERUINT16usIndex; REGISTERPLW_CLASS_TCBptcb; REGISTERPLW_CLASS_THREADVARpthreadvar; usIndex = _ObjectGetIndex(ulId); ... } |
判断是否在中断
获取CPU当前的中断嵌套值,判断是否在中断,该函数不能在中断中调用。具体实现如程序清单 2-2所示。程序清单 2-2
判断是否在中断
if (LW_CPU_GET_CUR_NESTING()) { /* 不能在中断中调用 */ _DebugHandle(__ERRORMESSAGE_LEVEL, "called from ISR.\r\n"); _ErrorHandle(ERROR_KERNEL_IN_ISR); return (ERROR_KERNEL_IN_ISR); } |
检查线
4000
程的有效性
在进入内核态之前,检查当前线程ID是否符合线程规范,以判断该线程是否有效。具体实现如程序清单 2-3所示。程序清单 2-3
检查线程有效性
#if LW_CFG_ARG_CHK_EN > 0 if (!_ObjectClassOK(ulId, _OBJECT_THREAD)) { _DebugHandle(__ERRORMESSAGE_LEVEL, "thread handle invalidate.\r\n"); _ErrorHandle(ERROR_KERNEL_HANDLE_NULL); return (ERROR_KERNEL_HANDLE_NULL); } if (_Thread_Index_Invalid(usIndex)) { /* 检查线程有效性 */ _DebugHandle(__ERRORMESSAGE_LEVEL, "thread handle invalidate.\r\n"); _ErrorHandle(ERROR_THREAD_NULL); return (ERROR_THREAD_NULL); } #endif |
进入内核态
进入内核态进行操作。检查线程的有效性
进入内核态以后,通过检查对应的线程TCB地址表来判断线程是否有效。具体实现如程序清单 2-4所示。程序清单 2-4
检查线程有效性
if (_Thread_Invalid(usIndex)) { __KERNEL_EXIT(); /* 退出内核 */ _DebugHandle(__ERRORMESSAGE_LEVEL, "thread handle invalidate.\r\n"); _ErrorHandle(ERROR_THREAD_NULL); return (ERROR_THREAD_NULL); } |
分配控制块
为当前的线程分配一个私有数据控制块,通过Allocate_ThreadVar_Object函数从空闲ThreadVar 控件池中取出一个空闲 ThreadVar。具体实现如程序清单 2-5所示。程序清单 2-5
分配控制块
pthreadvar = _Allocate_ThreadVar_Object(); /* 分配一个控制块 */ |
检查控制块的有效性
判断获得的控制器是否有效。具体实现如程序清单 2-6所示。程序清单 2-6
检查控制块的有效性
if (!pthreadvar) { __KERNEL_EXIT(); /* 退出内核 */ _ErrorHandle(ERROR_THREAD_VAR_FULL); return (ERROR_THREAD_VAR_FULL); } |
链接控制块
将获得的私有数据控制块加入TCB的上下文。具体实现如程序清单 2-7所示。程序清单 2-7
链接控制块
pthreadvar->PRIVATEVAR_pulAddress = pulAddr; pthreadvar->PRIVATEVAR_ulValueSave = *pulAddr; ptcb = _K_ptcbTCBIdTable[usIndex]; /* 加入TCB上下文 */ _List_Line_Add_Ahead(&pthreadvar->PRIVATEVAR_lineVarList, &ptcb->TCB_plinePrivateVars); |
退出内核
退出内核态。删除线程私有变量
删除线程私有变量的流程如图 2-2所示。图 2-2
删除线程私有变量
输入
在调用API_ThreadVarDelete函数时,我们需要输入线程ID以及私有变量地址。具体实现如程序清单 2-8所示。程序清单 2-8
删除线程私有数据输入
ULONGAPI_ThreadVarDelete (LW_OBJECT_HANDLEulId, ULONG *pulAddr) { REGISTERUINT16usIndex; REGISTERPLW_CLASS_TCBptcbCur; REGISTERPLW_CLASS_TCBptcb; REGISTERPLW_LIST_LINEplineVar; REGISTERPLW_CLASS_THREADVARpthreadvar; usIndex = _ObjectGetIndex(ulId); … } |
判断是否在中断
获取CPU当前的中断嵌套值,判断是否在中断,该函数不能在中断中调用。检查线程的有效性
在进入内核态之前,检查当前线程ID是否符合线程规范,以判断该线程是否有效。进入内核态
进入内核态进行操作。检查线程的有效性
进入内核态以后,通过检查对应的线程TCB地址表来判断线程是否有效。查找私有数据控制块并解链
通过全局变量私有化线表查找控制块,将私有数据控制块从TCB中解链并释放控制块。具体实现如程序清单 2-9所示。程序清单 2-9
查找控制块并解链
for (plineVar = ptcb->TCB_plinePrivateVars; /* 查找 */ plineVar != LW_NULL; plineVar = _list_line_get_next(plineVar)) { pthreadvar = _LIST_ENTRY(plineVar, LW_CLASS_THREADVAR, PRIVATEVAR_lineVarList); if (pthreadvar->PRIVATEVAR_pulAddress == pulAddr) { if (ptcb == ptcbCur) { *pulAddr = pthreadvar->PRIVATEVAR_ulValueSave; } _List_Line_Del(plineVar, &ptcb->TCB_plinePrivateVars); /* 从 TCB 中解链 */ _Free_ThreadVar_Object(pthreadvar); /* 释放控制块 */ __KERNEL_EXIT(); /* 退出内核 */ return (ERROR_NONE); } } |
退出内核
退出内核态。设置私有线程变量
设置线程私有变量的流程如图 2-3所示。图 2-3
设置线程私有变量
输入
在调用API_ThreadVarSet函数时,我们需要输入线程ID以及私有变量地址。具体实现如程序清单 2-10所示。程序清单 2-10
设置线程私有变量的值输入
ULONG API_ThreadVarSet (LW_OBJECT_HANDLEulId, ULONG *pulAddr, ULONGulValue) { REGISTERUINT16usIndex; REGISTERPLW_CLASS_TCBptcbCur; REGISTERPLW_CLASS_TCBptcb; REGISTERPLW_LIST_LINEplineVar; REGISTERPLW_CLASS_THREADVARpthreadvar; usIndex = _ObjectGetIndex(ulId); … } |
判断是否在中断
获取CPU当前的中断嵌套值,判断是否在中断,该函数不能在中断中调用。检查线程的有效性
在进入内核态之前,检查当前线程ID是否符合线程规范,以判断该线程是否有效。进入内核态
进入内核态进行操作。检查线程的有效性
进入内核态以后,通过检查对应的线程TCB地址表来判断线程是否有效。查找私有数据控制块同时判断是否为当前线程
通过全局变量私有化线表查找控制块,然后检查线程控制块的相关信息判断是否为当前线程,是则赋值,不是则将值保存。具体实现如程序清单 2-11所示。程序清单 2-11
查找控制块并判断是否为当前线程
ptcb = _K_ptcbTCBIdTable[usIndex]; for (plineVar = ptcb->TCB_plinePrivateVars; /* 查找 */ plineVar != LW_NULL; plineVar = _list_line_get_next(plineVar)) { pthreadvar = _LIST_ENTRY(plineVar, LW_CLASS_THREADVAR, PRIVATEVAR_lineVarList); if (pthreadvar->PRIVATEVAR_pulAddress == pulAddr) { if (ptcb == ptcbCur) { /* 是不是当前线程 */ *pulAddr = ulValue; } else { pthreadvar->PRIVATEVAR_ulValueSave = ulValue; } |
退出内核
退出内核态。获得线程私有变量值
获得线程私有变量值的流程如图 2-4所示。图 2-4
获得线程私有变量值
输入
我们需要输入线程ID以及私有变量地址。具体实现如程序清单 2-12所示。程序清单 2-12
私有线程变量值获取
ULONG API_ThreadVarGet (LW_OBJECT_HANDLE ulId, ULONG *pulAddr) { REGISTERUINT16usIndex; REGISTERPLW_CLASS_TCBptcbCur; REGISTERPLW_CLASS_TCBptcb; REGISTERPLW_LIST_LINEplineVar; REGISTERULONGulValue; REGISTERPLW_CLASS_THREADVARpthreadvar; usIndex = _ObjectGetIndex(ulId); … } |
判断是否在中断
获取CPU当前的中断嵌套值,判断是否在中断,该函数不能在中断中调用。检查线程的有效性
在进入内核态之前,检查当前线程ID是否符合线程规范,以判断该线程是否有效。进入内核态
进入内核态进行操作。检查线程的有效性
进入内核态以后,通过检查对应的线程TCB地址表来判断线程是否有效。查找私有数据控制块同时判断是否为当前线程
通过全局变量私有化线表查找控制块,然后检查线程控制块的相关信息判断是否为当前线程,是获取线程私有变量的值,不是则获得保存的变量值。实现如程序清单 2-13所示。程序清单 2-13
查找控制块并判断是否为当前线程
ptcb = _K_ptcbTCBIdTable[usIndex]; for (plineVar = ptcb->TCB_plinePrivateVars; /* 查找 */ plineVar != LW_NULL; plineVar = _list_line_get_next(plineVar)) { pthreadvar = _LIST_ENTRY(plineVar, LW_CLASS_THREADVAR, PRIVATEVAR_lineVarList); if (pthreadvar->PRIVATEVAR_pulAddress == pulAddr) { if (ptcb == ptcbCur) { /* 是不是当前线程 */ ulValue = *pulAddr; } else { ulValue = pthreadvar->PRIVATEVAR_ulValueSave; } |
退出内核
退出内核态。总结
线程私有数据是线程上下文记录的一个unsigned long型数值(可以将其看成一个指向一个全局变量的指针)和保存全局变量值的临时变量(用来恢复线程上下文中全局变量的值)。每次线程被调入处理器时,系统根据该指针自动从线程上下文装入全局变量的值。相应地,任务被调出处理器时,系统根据该指针自动将全局变量的值保存到线程的上下文。参考文献
1.《SylixOS应用开发手册》2. SylixOS源码
相关文章推荐
- SylixOS线程私有数据浅析 推荐
- 线程的私有数据
- linux api笔记(6):线程(四) 线程私有数据
- unix/linux下线程私有数据实现原理及使用方法
- linux线程之线程私有数据 pthread_key_create方法的学习
- 线程私有数据
- Posix线程编程指南(2)——线程私有数据
- 线程私有数据的介绍与使用(TSD)
- linux下C语言多线程(二)线程的私有数据
- 线程私有数据(TSD)
- 线程控制--私有数据
- 12.6 线程控制_线程私有数据
- pthread线程私有数据
- 线程私有数据(Thread-Specific Data)
- 线程私有数据thread-specific
- 线程控制-私有数据 转自monalisa's_blog
- 线程与私有数据
- 线程私有数据(Thread-specific Data,或TSD)
- linux下C语言多线程(二)线程的私有数据
- 线程私有数据TSD