预留内存携带附加信息的设计.DOC

上传人:天*** 文档编号:966520 上传时间:2018-11-10 格式:DOC 页数:4 大小:49.50KB
下载 相关 举报
预留内存携带附加信息的设计.DOC_第1页
第1页 / 共4页
预留内存携带附加信息的设计.DOC_第2页
第2页 / 共4页
预留内存携带附加信息的设计.DOC_第3页
第3页 / 共4页
预留内存携带附加信息的设计.DOC_第4页
第4页 / 共4页
亲,该文档总共4页,全部预览完了,如果喜欢就下载吧!
资源描述

1、预留内存携带附加信息的设计有时候,将数据与一个对象的实例关联起来是很有帮助的。这种设计要求预留一定的内存,一倍特定附加数据的存储。通过调用 SetWindowWord 或 SetWindowLong 函数将数据与一个指定的窗口关联起来,数据保存在窗口附加内存块中。窗口内存块即是一种窗口对象(HWND)的附加数据(window extra bytes),参考WNDCLASS.cbWndExtra 字段(Specifies the number of extra bytes to allocate following the window instance.)。这种预留附加的设计,在 MFC 中处

2、处可见。对于下拉选择列表(CComboBox)、下拉列表框、列表视图和树控件,我们不光希望其能显示条目内容(item text),还希望每个条目能够携带附加信息,即存储额外的关联数据(item data),以备不时之需。这四个控件都提供了SetItemData/GetItemData 接口,供用户储存关联数据。存储的数据为DWORD 值类型,可以是简单的数值,也可以存储指针。线程消息队列和_ptiddata我们在编写第一个 SDK 窗口程序时,就接触到了消息这一重要概念。实际上,消息队列是一种线程私有数据,每一个 Windows 程序的 UI(CUI/GUI)线程都维持了一个消息队列。GetM

3、essage、TranslateMessage、DispatchMessage 等对消息的操作都是与调用线程的消息队列息息相关。PostThreadMessage 是线程消息投递函数,它向一个指定 ID( idThread)的线程发送一条消息,然后不等处理立即返回。这个 API 在多线程架构程序中非常有用。 PostQuitMessage 是结束线程运行,相当于 nExitCode 作为 WM_QUIT 消息参数调用PostThreadMessage。调用线程收到该消息后即 ExitThread,故该函数一般用来响应 WM_DESTROY 消息。尽管秉持封装的原则,我们极力强调避免使用全局变量

4、,但全局变量对于进程级和线程级的系统统筹管理却是非常有用。除了消息队列这种系统内置的线程私有数据外,Windows 提供了线程局部存储系统( TLS,Thread Local Storage),为用户提供了存储与线程关联数据的接口。前面提到的_beginthreadex 中分配的 _ptiddata(pointer to per-thread data),即使用了 TLS。_ptiddata 为 Windows 平台的多线程程序中,strtok、strerror(errno)等依赖全局变量或静态变量的 CRT 函数的实现提供了有效的解决方案。Win32 线程局部存储系统用于管理 TLS 的数据

5、结构是很简单的,Windows 仅为系统中的每一个进程维护一个位数组,再为该进程中的每一个线程申请一个同样长度的数组空间,如下图所示。在 Windbg 中,可以窥探 TEB 中的 TLS 数据结构。lkd dt _tebnt!_TEB+0x02c ThreadLocalStoragePointer : Ptr32 Void+0xe10 TlsSlots : 64 Ptr32 Void+0xf10 TlsLinks : _LIST_ENTRY+0xf94 TlsExpansionSlots : Ptr32 Ptr32 Voidtypedef struct _TEB / 66 elements,

6、0xFB8 bytes (sizeof)/ /*0x02C*/ VOID* ThreadLocalStoragePointer;/ /*0xE10*/ VOID* TlsSlots64;/*0xF10*/ struct _LIST_ENTRY TlsLinks; / 2 elements, 0x8 bytes (sizeof)/ /*0xF94*/ VOID* TlsExpansionSlots;/ TEB, *PTEB;当一个线程被创建时,Windows 就会在进程地址空间中为该线程分配一个长度为 TLS_MINIMUM_AVAILABLE 的数组,数组成员的值都被初始化为 0。在内部,系统

7、将此数组与该线程关联起来,保证只能在该线程中访问此数组中的数据。如上图所示,每个线程都有它自己的数组,数组成员可以存储任何数据。运行在系统中的每一个进程都有上图所示的一个位数组。位数组的成员是一个标志,每个标志的值被设为 FREE 或 INUSE,指示了此标志对应的数组索引是否在使用中。Windows 保证至少有 TLS_MINIMUM_AVAILABLE(定义在 WinNT.h 文件中)个标志位可用。动态使用 TLS 典型步骤如下。(1)主线程调用 TlsAlloc 函数为线程局部存储分配索引,函数原型如下。DWORD TlsAlloc(VOID);TlsAlloc 为我们预订了一个索引。如

8、果 TlsAlloc 返回的索引为 3,那等于说索引 3 已经被我们预订了,无论是进程中当前正在运行的线程,还是今后可能会创建的线程,都不能再使用索引 3。(2)每个线程调用 TlsSetValue 和 TlsGetValue 设置或读取线程数组中的值,这两个函数的原型如下。BOOL TlsSetValue(DWORD dwTlsIndex, / TLS indexLPVOID lpTlsValue / value to store);LPVOID TlsGetValue(DWORD dwTlsIndex / TLS index);(3)主线程调用 TlsFree 释放局部存储索引。函数的惟一

9、参数是TlsAlloc 返回的索引。BOOL TlsFree(DWORD dwTlsIndex / TLS index);MFC 中的线程局部存储如果你需要大量的数据贯穿一个线程,普通的 TLS 索引一个值就会变得不实用,Windows 的 TLS 只允许用户保存一个 32 位的指针。如果需要用户保存任意类型的数据(包含整个类)。这个任意大小的数据所占的内存通常是在进程的堆中分配,所以当用户释放全局索引时,系统必须将每个线程内此数据占用的内存释放掉,这就要求系统把为各线程分配的内存都记录下来。较好的方法是将各个私有数据的首地址用一个链表连在一起,释放全局索引时只要遍历此链表,就可以逐个释放线程

10、私有数据占用的空间了。例如,有下面一个存放线程私有数据的数据结构。struct CThreadDataCThreadData* pNext; / 指向下一个线程的 CThreadData 结构的指针LPVOID pData; / 指向真正的线程私有数据的指针;指针 pData 指向为线程分配的内存的首地址,指针 pNext 将各线程的数据连在了一起。这实际上是一种二级指针的分槽存储。MFC 的线程局部存储类CThreadLocal 即实现了二级指针的分槽存储。MFC 框架的状态信息也是理解的难点,包括模块状态AFX_MODULE_STATE、线程状态 _AFX_THREAD_STATE 和模块

11、线程状态AFX_MODULE_THREAD_STATE。这些线程级别的全局状态维持即使用了线程局部存储(TLS )。参考李久进著作的MFC 深入浅出第九章MFC 的状态。由于 MFC 广泛地应用了线程局部存储,故在 MFC 下,使用线程必须格外小心。许多 MFC 对象仅在创建它们的线程内运作。一般地,具有句柄映射的任何对象都不能从其他线程访问该对象。例如,模块线程状态AFX_MODULE_THREAD_STATE 中的 CHandleMap* m_pmapHWND 映射记录了MFC 线程中创建的 CWnd 对象实例与内核窗口句柄(HWND)之间的映射消息。内核窗口句柄是可以进程访问级别,因此可

12、跨线程访问。但是试图传递 CWnd对象实例以期跨线程操作,往往失败。因为另一个引用线程并未像创建线程那样维系一个映射,所以当需要 CWndHWND 以执行 API 操作时,往往找不到其所指窗口。针对以上问题,通常优先传送句柄,避免在线程之间传送 MFC 对象。在引用线程中将其转换为临时 MFC 对象。例如,假设线程 A 创建一个 CWnd 对象。线程 A 并不将对象传送给线程 B,而将该对象的 m_hWnd 成员传送给线程 B。于是,线程 B 可以调用 CWnd:FromHandle,以创建一个临时的 CWnd 对象。如果线程 B 需要更持久的连接,就可以使用 Attach 方法,在窗口及其 CWnd对象之间建立持久的关联。另外的一个常见问题是 MFC 对象访存的线程安全性问题。MFC 对象不会自动在不同的线程之间做出判断。所以,如果两个线程试图同时访问同一个CString 类的对象,结果可能受到严重破坏。只有防止来自有冲突的 MFC 对象的线程。通常,这将需要使用前面提到的同步机制,以保证多线程数据交换的一致性。

展开阅读全文
相关资源
相关搜索

当前位置:首页 > 重点行业资料库 > 1

Copyright © 2018-2021 Wenke99.com All rights reserved

工信部备案号浙ICP备20026746号-2  

公安局备案号:浙公网安备33038302330469号

本站为C2C交文档易平台,即用户上传的文档直接卖给下载用户,本站只是网络服务中间平台,所有原创文档下载所得归上传人所有,若您发现上传作品侵犯了您的权利,请立刻联系网站客服并提供证据,平台将在3个工作日内予以改正。