Meyers如何实现Singleton实际上是一个Singleton [英] How is Meyers' implementation of a Singleton actually a Singleton
问题描述
我已经阅读了很多关于Singletons,当他们应该和不应该使用,以及如何安全地实施它们。我在C ++ 11中编写,并且遇到了Meyer的一个单例的惰性初始化实现,如这个问题。
这个实现是:
static Singleton& instance()
{
static Singleton s;
return s;
}
我理解这是线程如何从其他问题在这里SO,我不明白是怎么这实际上是一个单例模式。我已在其他语言中实现单例,并且这些常见的例子来自维基百科:
public class SingletonDemo {
private static volatile SingletonDemo instance = null;
private SingletonDemo(){}
public static SingletonDemo getInstance(){
if(instance == null){
synchronized(SingletonDemo .class ){
if(instance == null){
instance = new SingletonDemo();
}
}
}
return instance;
}
}
当我看第二个例子时,直觉这是一个单例,因为类保存对自身的一个实例的引用,并且只有返回该实例。但是,在第一个例子中,我不明白这是如何防止存在的对象的两个实例。所以我的问题是:
- 第一个实现如何强制实施单例模式?我假设它与static关键字有关,但我希望有人可以深入解释发生的事情。
- 在这两种实现风格之间,是一个优选在另一个?
- How does the first implementation enforce a singleton pattern? I assume it has to do with the static keyword, but I am hoping that someone can explain to me in depth what is happening under the hood.
- Between these two implementation styles, is one preferable over the other? What are the pros and cons?
感谢任何帮助,
这是一个单例,因为 static
函数local的存储持续时间意味着程序中只存在该局部的一个实例。
在这种情况下,这可以被认为等同于下面的C ++ 98(甚至可能由编译器模糊地实现):
static bool __guard = false;
static char __storage [sizeof(Singleton)]; //也对齐它
Singleton& Instance(){
if(!__ guard){
__guard = true;
new(__storage)Singleton();
}
return * reinterpret_cast< Singleton *>(__ storage);
}
//当进程退出时自动调用
void __destruct(){
if(__guard)
reinterpret_cast< Singleton *> ) - >〜Singleton();
}
线程安全位使它变得更复杂,同样的事情。
看一下C ++ 11的实际实现,每个静态都有一个 guard变量 ,其也用于屏障和螺纹。看看Clang的AMD64输出:
Singleton& instance(){
static Singleton实例;
return instance;
}
实例的AMD64程序集
从Ubuntu的Clang 3.0 on AMD64 at -O1(由 http://gcc.godbolt.org/ 提供)是:
instance():#@instance()
pushq%rbp
movq%rsp,%rbp $ b b movb guard实例的变量():: instance(%rip),%al
testb%al,%al
jne .LBB0_3
movl guard变量, %edi
callq __cxa_guard_acquire
testl%eax,%eax
je .LBB0_3
movl instance():: instance,%edi
callq Singleton :: Singleton
movl保护变量的实例()::实例,%edi
callq __cxa_guard_release
.LBB0_3:
movl instance():: instance,%eax
popq% rbp
ret
您可以看到它引用一个全局保护来查看是否需要初始化,使用 __ cxa_guard_acquire
,再次测试初始化,等等。几乎每一种方式,像从维基百科发布的版本,除了使用AMD64程序集和在中指定的符号/布局Itanium ABI 。
请注意,如果您运行该测试,您应该给 Singleton
构造函数,所以它不是一个POD,否则优化器会意识到没有任何意义,做所有的保护/锁定工作。
I have been reading a lot about Singletons, when they should and shouldn't be used, and how to implement them safely. I am writing in C++11, and have come across the Meyer's lazy initialized implementation of a singleton, as seen in this question.
This implementation is:
static Singleton& instance()
{
static Singleton s;
return s;
}
I understand how this is thread safe from other questions here on SO, but what I don't understand is how this is actually a singleton pattern. I have implemented singletons in other languages, and these always end up something like this example from Wikipedia:
public class SingletonDemo {
private static volatile SingletonDemo instance = null;
private SingletonDemo() { }
public static SingletonDemo getInstance() {
if (instance == null) {
synchronized (SingletonDemo .class){
if (instance == null) {
instance = new SingletonDemo ();
}
}
}
return instance;
}
}
When I look at this second example, it is very intuitive how this is a singleton, since the class holds a reference to one instance of itself, and only ever returns that instance. However, in the first example, I don't understand how this prevents there ever existing two instances of the object. So my questions are:
Thanks for any help,
This is a singleton because static
storage duration for a function local means that only one instance of that local exists in the program.
Under the hood, this can very roughly be considered to be equivalent to the following C++98 (and might even be implemented vaguely like this by a compiler):
static bool __guard = false;
static char __storage[sizeof(Singleton)]; // also align it
Singleton& Instance() {
if (!__guard ) {
__guard = true;
new (__storage) Singleton();
}
return *reinterpret_cast<Singleton*>(__storage);
}
// called automatically when the process exits
void __destruct() {
if (__guard)
reinterpret_cast<Singleton*>(__storage)->~Singleton();
}
The thread safety bits make it get a bit more complicated, but it's essentially the same thing.
Looking at an actual implementation for C++11, there is a guard variable for each static (like the boolean above), which is also used for barriers and threads. Look at Clang's AMD64 output for:
Singleton& instance() {
static Singleton instance;
return instance;
}
The AMD64 assembly for instance
from Ubuntu's Clang 3.0 on AMD64 at -O1 (courtesy of http://gcc.godbolt.org/ is:
instance(): # @instance()
pushq %rbp
movq %rsp, %rbp
movb guard variable for instance()::instance(%rip), %al
testb %al, %al
jne .LBB0_3
movl guard variable for instance()::instance, %edi
callq __cxa_guard_acquire
testl %eax, %eax
je .LBB0_3
movl instance()::instance, %edi
callq Singleton::Singleton()
movl guard variable for instance()::instance, %edi
callq __cxa_guard_release
.LBB0_3:
movl instance()::instance, %eax
popq %rbp
ret
You can see that it references a global guard to see if initialization is required, uses __cxa_guard_acquire
, tests the initialization again, and so on. Exactly in almost every way like version you posted from Wikipedia, except using AMD64 assembly and the symbols/layout specified in the Itanium ABI.
Note that if you run that test you should give Singleton
a non-trivial constructor so it's not a POD, otherwise the optimizer will realize that there's no point to doing all that guard/locking work.
这篇关于Meyers如何实现Singleton实际上是一个Singleton的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!