MFC框架之线程局部存储
线程局部存储中用到的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框架之线程局部存储的更多相关文章
- MFC学习-第2,3课 MFC框架的运行机制
转自:http://blog.163.com/zhigang0633@126/blog/static/38790491200822711526168/ 讲述MFC AppWizard的原理与MFC程序 ...
- Delphi管理多线程之线程局部存储:threadvar
尽管多线程能够解决许多问题,但是同时它又给我们带来了很多的问题.其中主要的问题就是:对全局变量或句柄这样的全局资源如何访问?另外,当必须确保一个线程中的某些事件要在另一个线程中的其他时间之前(或之后) ...
- 【windows核心编程】线程局部存储TLS
线程局部存储TLS, Thread Local Storage TLS是C/C++运行库的一部分,而非操作系统的一部分. 分为动态TSL 和 静态TLS 一.动态TLS 应用程序通过调用一组4个函数来 ...
- 在MFC框架中使用OpenGL的简单实例
引言 我们知道,在MFC框架中,用于绘图的接口是GDI.但GDI只能绘制简单的2D图形,要想制作精美的3D图形,一个可行的办法是使用OpenGL或者Direct3D等第三方库. 由于最近在给导师的一个 ...
- MFC框架
第一点:类别型录网的搭建: 类别型录网搭建的目的是为了实现所谓的"执行期类型识别",也就是在程序运行的时候识别出某个对象是否是某个类的实例(基类也可以).这里还不是很明白为什么需要 ...
- MFC框架中消失的WinMain()
学过一段时间的MFC之后,很多人大概都有一个疑问:在MFC中,WinMain()哪去了?因为任何一个使用过Win32 SDK编程的人都知道,WinMain()函数是Win32程序开始的入口点,可是在M ...
- 对MFC 框架的认识
1.MFC 的概念 微软基础类库(英语:Microsoft Foundation Classes,简称MFC)是一个微软公司提供的类库(class libraries),以C++类的形式封装了Wind ...
- MFC多线程各种线程用法 .
http://blog.csdn.net/qq61394323/article/details/9328301 一.问题的提出 编写一个耗时的单线程程序: 新建一个基于对话框的应用程序SingleTh ...
- PE格式第八讲,TLS表(线程局部存储)
PE格式第八讲,TLS表(线程局部存储) 作者:IBinary出处:http://www.cnblogs.com/iBinary/版权所有,欢迎保留原文链接进行转载:) 一丶复习线程相关知识 首先讲解 ...
随机推荐
- csdn 不登录浏览全文 chrome 浏览器
1将此文章存到书签栏. 2 右键点击保存到书签栏的这个书签,然后点击修改. 3 名称改为:CSDN查看全文,网址改为: javascript:$("#article_content" ...
- php file_get_contents fopen 连接远程文件
使用file_get_contents和fopen必须空间开启allow_url_fopen. 方法: 编辑php.ini,设置allow_url_fopen =true On,allow_url_f ...
- Martin Fowler 分层测试概念博文分享
在我们测试工作中,常常遇到这样的问题:开发与测试团队分属不同的不同(部门隔离.沟通不畅),质量职责划分不清(出现bug往往都是测试人员背锅),需求的不确定和易变性(需求不断变化导致代码不停更新.产品重 ...
- ASP.NET MVC5 高级编程-学习日记-第三章 视图
开发人员之所以花费大量时间来重点设计控制器和模型对象,是因为在这些领域中,精心编写的整洁代码是开发一个可维护Web应用程序的基础. 3.1 视图的作用 视图的职责是向用户提供用户界面.当控制器针对被请 ...
- AreaHttpControllerSelector 对 Web Api 实现 Area 路由控制
结合此文章:http://www.cnblogs.com/wuhuacong/p/5828038.html using System; using System.Collections.Concurr ...
- ovs-appctl 命令合集
通用命令 exit 优雅关闭ovs-vswitchd进程 qos/show interface 查询内核中关于qos的配置以及和给出端口有关的状态 cfm/show [interface]显示在指定端 ...
- js获取当前页面相关信息
1. 获取整个url: console.log(window.location.href) http://localhost:8082/Index.html?name=tom 2. 获取域名加端口号 ...
- 05-创建kubectl-kubeconfig文件
本文档介绍创建 kubeconfig 文件 下载 kubectl $ wget https://dl.k8s.io/v1.6.0/kubernetes-client-linux-amd64.tar.g ...
- centos7 系统优化
#!/usr/bin/env bash #设置环境变量 export PATH=$PATH:/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/u ...
- POJ 2685
#include <iostream> #include <string> #define MAXN 26 using namespace std; int _map[MAXN ...