mac*_*ler 6 c winapi multithreading thread-local-storage
在 MSDN 中阅读以下页面:
我无法理解在FreeLibrary()调用的情况下谁负责释放每个线程的 TLS 插槽指向的内存。
据我了解,如果我有多个正在运行的线程,它们都会在给定索引中的 TLS 插槽内分配内存。当FreeLibrary()被调用时, onlyDLL_PROCESS_DETACH被触发,因此只有收到DLL_PROCESS_DETACH通知的线程才有机会LocalFree()在调用TlsFree()索引之前调用存储在 TLS 插槽中的自己的数据。这会导致所有没有机会调用LocalFree()其数据的其他线程发生内存泄漏,因为它们没有收到DLL_THREAD_DETACH通知。
有人可以解释应该在何时何地释放存储在每个线程的 TLS 插槽中的缓冲区吗?
根据您链接到的文档:
当线程终止时,使用 DLL_THREAD_DETACH 值调用入口点函数,并释放该线程的内存。
这是应该释放 TLS 插槽指向的内存的理想时间,如果线程在终止之前还没有这样做的话。这在提供的示例代码中进行了演示:
case DLL_THREAD_DETACH:
// Release the allocated memory for this thread.
lpvData = TlsGetValue(dwTlsIndex);
if (lpvData != NULL)
LocalFree((HLOCAL) lpvData);
break;
case DLL_PROCESS_DETACH:
// Release the allocated memory for this thread.
lpvData = TlsGetValue(dwTlsIndex);
if (lpvData != NULL)
LocalFree((HLOCAL) lpvData);
// Release the TLS index.
TlsFree(dwTlsIndex);
break;
Run Code Online (Sandbox Code Playgroud)
但是,根据DllMain 入口点文档:
当由于 DLL 加载失败、进程终止或调用
FreeLibraryDLL 从进程中卸载 DLL 时,系统不会DLL_THREAD_DETACH使用进程的各个线程的值调用 DLL 的入口点函数. 仅向 DLL 发送DLL_PROCESS_DETACH通知。DLL 可以借此机会为 DLL 已知的所有线程清理所有资源。
因此,您必须跟踪存储在每线程 TLS 插槽中的指针,以便DLL_THREAD_DETACH处理程序稍后可以释放任何尚未被处理程序释放的指针DLL_PROCESS_DETACH。例如,通过将指针存储在全局线程安全列表中。
更新:另一种解决方案是让DLL_PROCESS_DETACH处理程序枚举正在运行的线程,访问每个线程的 TIB/TEB(线程信息/环境块)结构。NtQueryInformationThread()可用于检索指向线程的 TIB/TEB 的指针。除此之外,TIB/TEB 还包含一个指向线程的 TLS 数组的指针。
更新:在 Vista+ 上,另一种解决方案是使用 FLS(光纤本地存储)而不是 TLS(线程本地存储)。该FlsAlloc()函数采用可选的回调。该FlsCallback文件指出:
应用程序定义的函数。如果正在使用 FLS 插槽,则在纤程删除、线程退出和FLS 索引被释放时调用 FlsCallback 。
并且FlsFree()文档指出:
释放 FLS 索引会释放当前进程中所有 FLS 实例的索引。如果相应的 FLS 槽包含非 NULL 值,则释放 FLS 索引还会导致为每个光纤调用关联的回调例程。
根据纤维文档:
光纤可以使用光纤本地存储 (FLS) 为每个光纤创建唯一的变量副本。如果没有发生光纤切换,FLS 的行为与线程本地存储完全相同。的FLS函数(
FlsAlloc,FlsFree,FlsGetValue,和FlsSetValue)操作与当前线程相关联的FLS。如果线程正在执行一个纤程并且该纤程被切换,则 FLS 也被切换。
| 归档时间: |
|
| 查看次数: |
758 次 |
| 最近记录: |