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/版权所有,欢迎保留原文链接进行转载:) 一丶复习线程相关知识 首先讲解 ...
随机推荐
- Linux-用户及权限
1. 用户组 RHEL 7/CentOS 7系统中的用户组有如下3类: 超级用户,UID 0:系统的超级用户. 系统用户,UID 1-999:系统中系统服务由不同用户运行,更加安全,默认被限制不能登录 ...
- [NewCode 4] 替换空格
题目描述 请实现一个函数,将一个字符串中的空格替换成"%20".例如,当字符串为We Are Happy.则经过替换之后的字符串为We%20Are%20Happy. 最直接的方式, ...
- StringBuilder 详解 (String系列之2)
本章介绍StringBuilder以及它的API的详细使用方法. 转载请注明出处:http://www.cnblogs.com/skywang12345/p/string02.html StringB ...
- Spring IOC 容器源码分析 - 获取单例 bean
1. 简介 为了写 Spring IOC 容器源码分析系列的文章,我特地写了一篇 Spring IOC 容器的导读文章.在导读一文中,我介绍了 Spring 的一些特性以及阅读 Spring 源码的一 ...
- 如何查看 Ubuntu下已安装包版本号
原文链接:https://www.cnblogs.com/the-tops/p/8350662.html 一个软件工具叫做apt-show-versions,通过apt-get安装: $sudo ap ...
- python常用代码片段
目录 Python3常用 文件处理 json处理 log日志 argparse使用 INIparser Python3常用 文件处理 class BaseMethod: @staticmethod d ...
- 使用Flask+uwsgi+Nginx部署Flask正式环境
环境准备 在开始正式讲解之前,我们将首先进行环境准备. Step1:安装Python,pip以及nginx: sudo apt-get update sudo apt-get install pyth ...
- [学习笔记]状压dp
状压 \(dp\) 1.[SDOI2009]Bill的挑战 \(f[i][j]\) 表示匹配到字符串的第 \(i\) 位状态为 \(j\) 的方案数 那么方程就很明显了,每次枚举第 \(i\) 位的字 ...
- Python 一篇学会多线程
多线程和多进程是什么自行google补脑,廖雪峰官网也有,但是不够简洁,有点晕,所以就整个简单的范例. 对于python 多线程的理解,我花了很长时间,搜索的大部份文章都不够通俗易懂.所以,这里力图用 ...
- linux防火墙(三)—— iptables语法之匹配条件
一.iptables规则的匹配条件类型有三类 1.通用匹配:可直接使用,不依赖于其他条件或扩展,包括网络协议.IP地址.网络接口等条件 2.隐含匹配:要求以特定的协议匹配作为前提,包括端口.TCP标记 ...