破坏Thread本地存储中的静态类成员

Gia*_*uca 6 c++ multithreading synchronization

我正在编写一个快速的多线程程序,我想避免同步(需要同步的函数必须被称为每秒5,000,000次,所以即使互斥量太大也是如此).

场景是:我有一个类的全局实例,每个线程都可以访问它.为了避免同步,类中的所有数据都是只读的,除了一堆类成员,然后在TLS中声明(使用__thread或__declspec(thread)).

不幸的是,为了使用编译器提供的__thread接口,类成员必须是静态的,没有构造函数/解构函数.我使用的类当然有自定义构造函数,所以我作为类成员声明指向这些类的指针(类似于静态__thread MyClass*_object).

然后,第一次线程从全局实例调用方法时,我会执行类似"(如果_object == NULL)object = new MyClass(...)"的操作.

我最大的问题是:是否有一种智能的方式来释放这个分配的内存?这个全局类来自一个库,并且它被程序中的许多线程使用,并且每个线程以不同的方式创建(即每个线程执行不同的函数),并且每次我都不能放置代码的snipplet线程将要终止.感谢你们.

Leo*_*son 2

TLS 清理通常在 DllMain 中传递 DLL_THREAD_DETACH 时完成。

如果您的代码全部位于 EXE 而不是 DLL 中,那么您可以创建一个虚拟 DLL,由 EXE 加载,然后在 DLL_THREAD_DETACH 上回调到 EXE。(我不知道有更好的方法让 EXE 代码在线程终止时运行。)

DLL 回调 EXE 的方法有两种:一种是 EXE 可以像 DLL 一样导出函数,并且 DLL 代码可以使用 EXE 模块句柄上的 GetProcAddress。一种更简单的方法是为 DLL 提供一个 init 函数,EXE 调用该函数来显式传递函数指针。

请注意,您在 DllMain 中可以执行的操作是有限的(不幸的是,这些限制没有正确记录),因此您应该尽量减少以这种方式完成的任何工作。不要运行任何复杂的析构函数;只需使用直接的 kernel32.dll API(如 HeapAlloc)释放内存并释放 TLS 插槽。

另请注意,对于加载 DLL 时已经运行的线程,您不会获得 DLL_THREAD_ATTACH(但如果它们在加载 DLL 时退出,您仍然会获得 DLL_THREAD_DETACH),并且您将(仅)获得 DLL_PROCESS_DETACH最终线程退出。