线程局部存储中用到的API基础:(TLS:Thread Local Storage)

1、在主线程中申请索引

g_index=::TlsAlloc();

2、在线程函数中使用索引

存值:::TlsSetValue(g_index,(LPVOID)value); value是要存入此线程私有空间的值;

取值: ::m_value=::TlsGetValue(g_index);

==================================================================

框架程序利用上面API基础封装了一套功能更加完善的线程局部存储类,之后会利用这个类实现框架中的“运行时类信息”、“线程状态”、“模块状态”、“模块线程状态”。

首先对于每个线程来说,其线程私有的数据空间数据结构如下:

struct CThreadData:public CNoTrackObject //(不必跟踪内存的使用)

{

CThreadData* pNext;  //指向下一个线程私有数据空间

int nCount;                  //pData数组元素个数

LPVOID* pData;         //实际存储数据的数组

}

CNoTrackObject类重写了new 操作符和delete操作符 减少了额外内存的使用,系统要求线程私有数据都应该从CNoTrackObject类继承。

为了管理线程私有数据空间,将上述各个线程的CThreadData结构连成一个表,使用模板类CTypedSimpleList管理它,

此时线程私有的数据空间数据结构可以是任何从CNoTrackObject类继承来的结构体(但结构体中的基本属性不变)。

例如:

struct MyThreadData:CNoTrackObject

{

MyThreadData * pNext;

int someData

}

CTypedSimpleList<MyThreadData *> list;

CTypedSimpleList提供了对线程局部数据空间链表的的“增”“删”“查”    ,它只提供对(MyThreadData)整体操作,改动里面的数据需要使用下面介绍的。

使用下面介绍的会利用CTypedSimpleList来访问其指定的线程的私有数据空间。

注意:链表首个元素的指针是void* 类型的 所以无法通过MyThreadData中的pNext指针访问下一个MyThreadData结构。因此创建CTypedSimpleList对象后需要调用

Construct(int n_NextOffset)设置next指针的偏移量,访问下一个MyThreadData都是通过n_NextOffset偏移量。(不懂为什么这样弄)

==============================================================

此时需要一个数组来记录CThreadData中pData数组成员的使用情况 数组元素结构如下(数组下标表示pData数组对应下标的使用情况)

struct CSlotData

{

DWORD dwFlags;   //pData数组中项的使用标志(分配/未分配)

HINSTANCE hInst;   //占用此数组项的模块

}

============================================================

之后通过CThreadSlotData类来管理整个线程局部存储的数据结构

构造函数CThreadSlotData()

初始化CTypedSimpleList对象设置偏移量;

初始化CSlotData数组未NULL;

使用API  g_index=::TlsAlloc()申请一个索引;(之后会把CThreadData结构存入g_index索引)

分配可以使用的槽号int AllocSlot() 返回槽号index

首先查看上次分配的槽号的下一个槽是否分配;

如果未分配直接分配。(更新部分维护数据)

否则遍历CSlotData数组查找未分配的槽;

如果不存在空槽则申请更多的空间,返回新申请的首个槽。

设置某个槽的数据指针 SetValue(int nSlot,void* pValue)

首先利用API  m_value=::TlsGetValue(g_index)返回私有数据空间指针,强转为CThreadData*

如果指针为NULL(首次使用线程私有数据)

则新建CThreadData并且初始化然后加入CThreadData链表(即CTypedSimpleList)为CThreadData*中pData申请m_nMax个内存空间

如果只是nSlot大于CThreadData中nCount(超出)则为CThreadData*中pData同样申请m_nMax个内存空间(m_nMax在分配nslot时肯定被增大了)

将新申请的内存初始化为0;

将CThreadData结构体 设回::TlsSetValue(g_index,(LPVOID)value);

设置结构体CThreadData中pData数组中的第nSlot项的值。

取得某个槽的值 GetThreadValue(int nSlot) 返回槽值

直接取::m_value=::TlsGetValue(g_index);强转为CThreadData*;

取得里面的值。如果取不到返回NULL。

删除某个槽的数据 FreeSlot(int nSlot)

遍历CThreadData链表依次删除nSlot槽中的数据

删除线程私有数据空间 DeleteValues(HINSTANCE hInst, BOOL bAll)  /  DeleteValues(CThreadData* pData, HINSTANCE hInst)

DeleteValues(HINSTANCE hInst, BOOL bAll)   //删除所有或一个(调用了DeleteValues(CThreadData* pData, HINSTANCE hInst))

DeleteValues(CThreadData* pData, HINSTANCE hInst)   //删除一个

================================================================

上面所实现的类是基于 CThreadData的线程局部存储结构,其中每个槽内存储的是指针并没有为这个指针分配内存空间,

现在想让槽中可以存用户自定义的任何数据类型并为其分配内存空间。

class CThreadLocalObject 类就是为此服务的。

主要函数GetData()参数为要存放的数据的构造函数(用来创建一个数据项)

首先取得分配槽  然后取得槽中的数据指针。

如果指针为空,则调用参数创建一个指定类型的变量。

================================================================

最后的接口

template<class TYPE>

class CThreadLocal::public CThreadLocalObject

{

public:

TYPE* GetData()

{

TYPE* pData=(TYPE*)CThreadLocalObject::GetData(&CreateObject);

return pData;

}

TYPE* GetDataNA()

{

TYPE* pData=(TYPE*)CThreadLocalObject::GetDataNA();

return pData;

}

operator TYPE *()       { return GetData();}

TYPE * operator-> ()   { return GetData();}

public:

static LPVOID CreateObject() {return new TYPE;}

}

此类重载了运算符 “*”和“->”

当你创建类对象时:

Struct CmyData:public CNoTrackObject

{

int  nNumber;

}

CThreadLocal<CmyData> m_Test;

m_Test->nNumber=20;  //申请一个槽并且存入CmyData类型指针,并且将其成员nNumber=20

m_Test直接会被当做CmyData结构指针来使用。

=================================================

完毕

MFC框架之线程局部存储的更多相关文章

  1. MFC学习-第2,3课 MFC框架的运行机制

    转自:http://blog.163.com/zhigang0633@126/blog/static/38790491200822711526168/ 讲述MFC AppWizard的原理与MFC程序 ...

  2. Delphi管理多线程之线程局部存储:threadvar

    尽管多线程能够解决许多问题,但是同时它又给我们带来了很多的问题.其中主要的问题就是:对全局变量或句柄这样的全局资源如何访问?另外,当必须确保一个线程中的某些事件要在另一个线程中的其他时间之前(或之后) ...

  3. 【windows核心编程】线程局部存储TLS

    线程局部存储TLS, Thread Local Storage TLS是C/C++运行库的一部分,而非操作系统的一部分. 分为动态TSL 和 静态TLS 一.动态TLS 应用程序通过调用一组4个函数来 ...

  4. 在MFC框架中使用OpenGL的简单实例

    引言 我们知道,在MFC框架中,用于绘图的接口是GDI.但GDI只能绘制简单的2D图形,要想制作精美的3D图形,一个可行的办法是使用OpenGL或者Direct3D等第三方库. 由于最近在给导师的一个 ...

  5. MFC框架

    第一点:类别型录网的搭建: 类别型录网搭建的目的是为了实现所谓的"执行期类型识别",也就是在程序运行的时候识别出某个对象是否是某个类的实例(基类也可以).这里还不是很明白为什么需要 ...

  6. MFC框架中消失的WinMain()

    学过一段时间的MFC之后,很多人大概都有一个疑问:在MFC中,WinMain()哪去了?因为任何一个使用过Win32 SDK编程的人都知道,WinMain()函数是Win32程序开始的入口点,可是在M ...

  7. 对MFC 框架的认识

    1.MFC 的概念 微软基础类库(英语:Microsoft Foundation Classes,简称MFC)是一个微软公司提供的类库(class libraries),以C++类的形式封装了Wind ...

  8. MFC多线程各种线程用法 .

    http://blog.csdn.net/qq61394323/article/details/9328301 一.问题的提出 编写一个耗时的单线程程序: 新建一个基于对话框的应用程序SingleTh ...

  9. PE格式第八讲,TLS表(线程局部存储)

    PE格式第八讲,TLS表(线程局部存储) 作者:IBinary出处:http://www.cnblogs.com/iBinary/版权所有,欢迎保留原文链接进行转载:) 一丶复习线程相关知识 首先讲解 ...

随机推荐

  1. Android-Recyclerview的简单使用

    由于Recyclerview是在 android.support.v7.widget.包 RecyclerView,所以需要导Recycler库: 导Recycler库: 选择项目,右键-->  ...

  2. 使用Code First建模自引用关系笔记

    原文链接 一.Has方法: A.HasRequired(a => a.B); HasOptional:前者包含后者一个实例或者为null HasRequired:前者(A)包含后者(B)一个不为 ...

  3. 【转】Windows IIS注册asp 此操作系统版本不支持此选项 错误解决方法

    原文:https://blog.csdn.net/sweety820/article/details/79538973 更新Win10,原来的IIS站点访问不了,原因是因为IIS 没有.net 4.5 ...

  4. 【转】C#中Serializable序列化实例详解

    这篇文章主要介绍了C#中Serializable序列化,以实例形式详细讲述了系列化的技术及各种序列化方法,非常具有实用价值,需要的朋友可以参考下 本文实例讲述了C#中Serializable序列化.分 ...

  5. JQuery 知识

    1.修改标签内容: *html( )  相当于innerHTML * text(  )  相当于innerText 2.属性操作: *attr(  )  读/写/添加/设置属性 *removeAttr ...

  6. Python-使用PyQT生成图形界面

    1.安装PyQT5以及QT Designer工具包 pip install PyQt5 pip install PyQt5-tools -i http://pypi.douban.com/simple ...

  7. DZY Loves Math(莫比乌斯反演)

    \(x=p_1^{\alpha_1}p_2^{\alpha_2}...p_c^{\alpha_c}\) \(f(x)=\max(\alpha_1,\alpha_2,...,\alpha_c)\) \( ...

  8. Redis---skipList(跳跃列表)

    1. 概述 跳跃表是一种有序的数据结构, 他通过在每个节点中维持多个指向其他节点的指针, 从而达到快速访问节点的目的. 大部分情况下, 跳跃表的效率可以和平衡树相媲美. Redis中只在两处用到了跳跃 ...

  9. zookeeper单机版安装

    ZooKeeper是一个分布式的,开放源码的分布式应用程序协调服务,是Google的Chubby一个开源的实现,是Hadoop和Hbase的重要组件.它是一个为分布式应用提供一致性服务的软件,提供的功 ...

  10. springBoot的搭建使用记录

    一: 首次搭建:https://blog.csdn.net/u013187139/article/details/68944972 整合mybatis: https://www.jianshu.com ...