由于使用Singleton模式实现logger的泛滥示例,我刚刚为我的程序编写了一个简单的C ++记录器。但是,由于已知着名的双重检查锁定方法不再是线程安全的,我想知道我是否应该:
1)忘记在这种情况下使用Singleton模式?
2)即使它不安全,继续使用双重检查锁定?
3)对每次访问公共接口使用昂贵的纯同步锁定方法吗?
有什么建议吗?
答案 0 :(得分:16)
使用Meyers Singleton。如果你使用gcc,至少初始化是线程安全的。
class Singleton{
Singleton(){
//This is threadsafe in gcc, no mutex required
}
static Singleton * instance(){
static Singleton myinstance;
return &myinstance;
}
};
gcc保护静态本地构造,除非你使用-fno-threadsafe-statics禁用,我最近写了here
答案 1 :(得分:1)
在具有线程的应用程序中,我更喜欢使用带有initialize()函数的单例,并断言以确保在第一个实例()之前使用了initialize()。从主线程调用initialize()。我不认为懒惰的实例化确实是单例的关键特性,特别是对于记录器。
虽然Arkaitz的答案更优雅,但我的答案避免了所有平台上的线程问题,其中包括1个额外函数的成本以及启动时对具有依赖性的单例的一些实例化关注(由断言和事件帮助:明智地使用单例)。
答案 2 :(得分:1)
一种方法是确保在应用启动第二个线程之前首次访问记录器。通过在您知道没有任何争用时访问单例,您可以确保后续访问将始终找到预先存在的对象,您应该完全避免该问题。
答案 3 :(得分:0)
你真的不需要单独的Initialize()函数,因为这会污染你的单例界面。只需获取单例实例
VERIFY(NULL != Logger::Instance());
在任何其他线程有机会访问它之前。