gpt4 book ai didi

c++ - 如何在 Windows 中创建线程安全的单例模式?

转载 作者:IT老高 更新时间:2023-10-28 22:18:23 27 4
gpt4 key购买 nike

我一直在这里阅读有关线程安全的单例模式:

http://en.wikipedia.org/wiki/Singleton_pattern#C.2B.2B_.28using_pthreads.29

它在底部说唯一安全的方法是使用 pthread_once - 这在 Windows 上不可用。

这是保证线程安全初始化的唯一方式吗?

我在 SO 上读过这个帖子:

Thread safe lazy construction of a singleton in C++

并且似乎暗示了原子操作系统级别的交换和比较功能,我假设在 Windows 上是:

http://msdn.microsoft.com/en-us/library/ms683568.aspx

这可以做我想做的事吗?

编辑:我想要延迟初始化并且永远只有一个类的实例。

另一个网站上的某个人提到在命名空间内使用全局变量(他将单例描述为反模式) - 它怎么可能是“反模式”?

接受的答案:
我接受了Josh's answer因为我使用的是 Visual Studio 2008 - 注意:对于 future 的读者,如果您不使用此编译器(或 2005) - 不要使用公认的答案!!

编辑:代码工作正常,除了 return 语句 - 我得到一个错误:错误 C2440:“return”:无法从“volatile Singleton *”转换为“Singleton *”。我应该将返回值修改为 volatile Singleton *?

编辑:显然 const_cast<> 将删除 volatile 限定符。再次感谢乔希。

最佳答案

保证单例的跨平台线程安全初始化的简单方法是在应用程序的主线程中显式执行(通过调用单例上的静态成员函数)< strong>在您的应用程序启动任何其他线程(或至少任何其他将访问单例的线程)。

然后使用互斥体/关键部分以通常的方式实现对单例的线程安全访问。

延迟初始化也可以使用类似的机制来实现。遇到的常见问题是提供线程安全所需的互斥锁通常在单例本身中初始化,这只会将线程安全问题推向互斥锁/关键部分的初始化。解决此问题的一种方法是在应用程序的主线程中创建和初始化互斥锁/临界区,然后通过调用静态成员函数将其传递给单例。然后可以使用这个预初始化的互斥体/临界区以线程安全的方式对单例进行重量级初始化。例如:

// A critical section guard - create on the stack to provide 
// automatic locking/unlocking even in the face of uncaught exceptions
class Guard {
private:
LPCRITICAL_SECTION CriticalSection;

public:
Guard(LPCRITICAL_SECTION CS) : CriticalSection(CS) {
EnterCriticalSection(CriticalSection);
}

~Guard() {
LeaveCriticalSection(CriticalSection);
}
};

// A thread-safe singleton
class Singleton {
private:
static Singleton* Instance;
static CRITICAL_SECTION InitLock;
CRITICIAL_SECTION InstanceLock;

Singleton() {
// Time consuming initialization here ...

InitializeCriticalSection(&InstanceLock);
}

~Singleton() {
DeleteCriticalSection(&InstanceLock);
}

public:
// Not thread-safe - to be called from the main application thread
static void Create() {
InitializeCriticalSection(&InitLock);
Instance = NULL;
}

// Not thread-safe - to be called from the main application thread
static void Destroy() {
delete Instance;
DeleteCriticalSection(&InitLock);
}

// Thread-safe lazy initializer
static Singleton* GetInstance() {
Guard(&InitLock);

if (Instance == NULL) {
Instance = new Singleton;
}

return Instance;
}

// Thread-safe operation
void doThreadSafeOperation() {
Guard(&InstanceLock);

// Perform thread-safe operation
}
};

但是,有充分的理由完全避免使用单例(以及为什么有时将它们称为反模式):

  • 它们本质上是美化的全局变量
  • 它们会导致应用程序不同部分之间的高度耦合
  • 它们可以使单元测试变得更加复杂或不可能(因为很难将真正的单例与假实现交换)

另一种方法是使用“逻辑单例”,您可以在主线程中创建和初始化一个类的单个实例,并将其传递给需要它的对象。如果您想将许多对象创建为单例,这种方法可能会变得笨拙。在这种情况下,可以将不同的对象捆绑到单个“上下文”对象中,然后在必要时传递。

关于c++ - 如何在 Windows 中创建线程安全的单例模式?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/164496/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com