您现在的位置是:首页 > 文章详情

SylixOS线程私有数据浅析

日期:2017-05-19点击:458

1.线程私有数据概述    1

2.线程私有数据的相关API函数流程浅析    1

2.1    加入线程私有变量    1

2.2    删除线程私有变量    3

2.3    设置私有线程变量    6

2.4    获得线程私有变量值    8

3.总结    10

4.参考文献    10

 

  1. 线程私有数据概述

    在SylixOS中为了满足多线程安全的要求,使得一种资源可以安全的被多个线程使用,采用了包括代码临界区保护和可重入性等方法。本文描述实现可重入的一种方法:线程私有数据。值得注意的是这种保护方式牺牲了系统的实时性并且只针对单CPU系统有效,若非必要,SylixOS不推荐使用此方式。

  2. 线程私有数据的相关API函数流程浅析

  3. 加入线程私有变量

    加入线程私有变量的流程如图 2-1所示。

    2-1加入线程私有变量

  4. 输入

    在调用API_ThreadVarAdd函数时,我们需要输入线程ID以及私有变量地址。具体实现如程序清单 2-1所示。

    程序清单 2-1加入线程私有变量输入

    ULONGAPI_ThreadVarAdd (LW_OBJECT_HANDLEulId,ULONG *pulAddr)

    {

    REGISTERUINT16usIndex;

    REGISTERPLW_CLASS_TCBptcb;

    REGISTERPLW_CLASS_THREADVARpthreadvar;

     

    usIndex =_ObjectGetIndex(ulId);

    ...

    }

  5. 判断是否在中断

    获取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);

    }

  6. 检查线程的有效性

    在进入内核态之前,检查当前线程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

  7. 进入内核态

    进入内核态进行操作。

  8. 检查线程的有效性

    进入内核态以后,通过检查对应的线程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);

    }

  9. 分配控制块

    为当前的线程分配一个私有数据控制块,通过Allocate_ThreadVar_Object函数从空闲ThreadVar 控件池中取出一个空闲 ThreadVar。具体实现如程序清单 2-5所示。

    程序清单 2-5分配控制块

    pthreadvar =_Allocate_ThreadVar_Object();/* 分配一个控制块 */

  10. 检查控制块的有效性

    判断获得的控制器是否有效。具体实现如程序清单 2-6所示。

    程序清单 2-6检查控制块的有效性

    if (!pthreadvar) {

    __KERNEL_EXIT();/* 退出内核 */

    _ErrorHandle(ERROR_THREAD_VAR_FULL);

    return (ERROR_THREAD_VAR_FULL);

    }

  11. 链接控制块

    将获得的私有数据控制块加入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);

  12. 退出内核

    退出内核态。

  13. 删除线程私有变量

    删除线程私有变量的流程如图 2-2所示。

    2-2删除线程私有变量

  14. 输入

    在调用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);

    }

  15. 判断是否在中断

    获取CPU当前的中断嵌套值,判断是否在中断,该函数不能在中断中调用。

  16. 检查线程的有效性

    在进入内核态之前,检查当前线程ID是否符合线程规范,以判断该线程是否有效。

  17. 进入内核态

    进入内核态进行操作。

  18. 检查线程的有效性

    进入内核态以后,通过检查对应的线程TCB地址表来判断线程是否有效。

  19. 查找私有数据控制块并解链

    通过全局变量私有化线表查找控制块,将私有数据控制块从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);

    }

    }

     
  20. 退出内核

    退出内核态。

  21. 设置私有线程变量

    设置线程私有变量的流程如图 2-3所示。

    2-3设置线程私有变量

  22. 输入

    在调用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);

    }

  23. 判断是否在中断

    获取CPU当前的中断嵌套值,判断是否在中断,该函数不能在中断中调用。

  24. 检查线程的有效性

    在进入内核态之前,检查当前线程ID是否符合线程规范,以判断该线程是否有效。

  25. 进入内核态

    进入内核态进行操作。

  26. 检查线程的有效性

    进入内核态以后,通过检查对应的线程TCB地址表来判断线程是否有效。

  27. 查找私有数据控制块同时判断是否为当前线程

    通过全局变量私有化线表查找控制块,然后检查线程控制块的相关信息判断是否为当前线程,是则赋值,不是则将值保存。具体实现如程序清单 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;

    }

  28. 退出内核

    退出内核态。

  29. 获得线程私有变量值

    获得线程私有变量值的流程如图 2-4所示。

    2-4获得线程私有变量值

  30. 输入

    我们需要输入线程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);

    }

  31. 判断是否在中断

    获取CPU当前的中断嵌套值,判断是否在中断,该函数不能在中断中调用。

  32. 检查线程的有效性

    在进入内核态之前,检查当前线程ID是否符合线程规范,以判断该线程是否有效。

  33. 进入内核态

    进入内核态进行操作。

  34. 检查线程的有效性

    进入内核态以后,通过检查对应的线程TCB地址表来判断线程是否有效。

  35. 查找私有数据控制块同时判断是否为当前线程

    通过全局变量私有化线表查找控制块,然后检查线程控制块的相关信息判断是否为当前线程,是获取线程私有变量的值,不是则获得保存的变量值。实现如程序清单 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;

    }

  36. 退出内核

    退出内核态。

     

  37. 总结

    线程私有数据是线程上下文记录的一个unsigned long型数值(可以将其看成一个指向一个全局变量的指针)和保存全局变量值的临时变量(用来恢复线程上下文中全局变量的值)。每次线程被调入处理器时,系统根据该指针自动从线程上下文装入全局变量的值。相应地,任务被调出处理器时,系统根据该指针自动将全局变量的值保存到线程的上下文。

  38. 参考文献

    1.《SylixOS应用开发手册》

    2. SylixOS源码

原文链接:https://blog.51cto.com/12833900/1927529
关注公众号

低调大师中文资讯倾力打造互联网数据资讯、行业资源、电子商务、移动互联网、网络营销平台。

持续更新报道IT业界、互联网、市场资讯、驱动更新,是最及时权威的产业资讯及硬件资讯报道平台。

转载内容版权归作者及来源网站所有,本站原创内容转载请注明来源。

文章评论

共有0条评论来说两句吧...

文章二维码

扫描即可查看该文章

点击排行

推荐阅读

最新文章