Voi*_*ter 4 c++ winapi singleton multithreading thread-local-storage
我想创建一个单例类,在每个使用它的线程中实例化一次.我想将实例指针存储在TLS插槽中.我已经提出了以下解决方案,但我不确定在涉及线程本地存储时是否对singelton工厂的多线程访问有任何特殊考虑.也许还有一个更好的解决方案来实现线程本地单例.
class ThreadLocalSingleton
{
static DWORD tlsIndex;
public:
static ThreadLocalSingleton *getInstance()
{
ThreadLocalSingleton *instance =
static_cast<ThreadLocalSingleton*>(TlsGetValue(tlsIndex));
if (!instance) {
instance = new ThreadLocalSingleton();
TlsSetValue(tlsIndex, instance);
}
return instance;
}
};
DWORD ThreadLocalSingleton::tlsIndex = TlsAlloc();
Run Code Online (Sandbox Code Playgroud)
Tls*功能当然是win32特定的,但便携性不是这里的主要问题.您对其他平台的想法仍然很有价值.
主要编辑:我最初询问在这种情况下使用双重检查锁定.然而正如DavidK指出的那样,无论如何都要在每个线程的基础上创建单例.
剩下的两个问题是:
是否适合回复TlsGetValue/TlsSetValue以确保每个线程获得一个实例并且每个线程只创建一次实例?
是否可以注册一个回调,允许我在该线程完成时清理与特定线程关联的实例?
Dav*_*idK 11
由于您的对象是线程本地的,为什么需要锁定来保护它们呢?调用getInstance()的每个线程都将独立于任何其他线程,那么为什么不检查单例是否存在并在需要时创建它?只有当多个线程试图访问相同的单例时才需要锁定,这在您的设计中是不可能的,如上所述.
编辑:转到另外两个问题......我看不出为什么使用TlsAlloc/TlsGetValue等没有任何理由可以按照您的预期运行.由于保存指向单例的指针的内存只能由相关线程访问,因此对它进行延迟初始化不会有任何问题.但是没有明确的回调接口来清理它们.
显而易见的解决方案是使用一个方法,由所有线程主函数调用,清除创建的单例,如果有的话.
如果线程很可能会创建一个singelton,一个更简单的模式可能是在线程main函数的开头创建单例并在结尾处删除它.然后,您可以通过在堆栈上创建单例,或者将其保存在std :: auto_ptr <>中来使用RAII,以便在线程结束时将其删除.(除非线程异常终止,但如果发生这种情况,所有投注都会被关闭,而泄漏的对象是您遇到的问题中最少的.)然后,您可以只传递单例,或将其存储在TLS中,或将其存储在一个成员中. class,如果大多数线程功能在一个类中.