【问题标题】:Thread safe singleton in C++C ++中的线程安全单例
【发布时间】:2012-08-12 09:23:04
【问题描述】:

我一直在阅读有关线程安全单例的信息,我发现到处都有一个 getInstance() 方法,如下所示:

Singleton* getInstance()
{
    if ( !initialized )
    {
        lock();
        if ( !initialized )
        {
            instance = new Singleton();
            initialized = true;
        }
        unlock();
    }

    return instance;
}
  • 这实际上是线程安全的吗?
  • 我是否遗漏了什么,或者该函数返回未初始化实例的可能性很小,因为“已初始化”可能会被重新排序并设置在实例之前?

这篇文章的主题略有不同,但最佳答案描述了为什么我认为上述代码不是线程安全的:

Why is volatile not considered useful in multithreaded C or C++ programming?

【问题讨论】:

  • 不,它不是线程安全的。而且,好吧,如果你使用单例,那么你就会得到你想要的,真的。
  • 或者简而言之,不是您错过了什么,而是该代码的作者。但是我想知道实例分配和初始化分配之间的内存障碍是否可以解决问题(假设初始化的类型为volatile sig_atomic_t)。
  • 记忆障碍也是我的想法。

标签: c++ multithreading design-patterns thread-safety singleton


【解决方案1】:

【讨论】:

  • 两篇优秀的程序员。感谢您发布这些内容。
【解决方案2】:

它确实不是线程安全的,因为在指针返回后你仍然可以使用它,尽管互斥锁再次解锁。

你可以做的是让继承自单例的子类,线程安全。那你就可以走了。

【讨论】:

    【解决方案3】:

    下面是线程安全单例的代码,使用了双重检查和临时变量。一个临时变量用于先完全构造对象,然后将其赋值给pInstance。

    Singleton* Singleton::instance() {
       if (pInstance == 0) {
          Lock lock;
          if (pInstance == 0) {
             Singleton* temp = new Singleton; // initialize to temp
             pInstance = temp; // assign temp to pInstance
          }
       }
       return pInstance;
    }
    

    【讨论】:

    • 这是 AProgrammer 答案中链接的文章中的确切代码。这篇文章解释了为什么这段代码不是线程安全的。 temp 变量将被优化掉。这些天来,我们有办法强制执行内存排序。
    猜你喜欢
    • 1970-01-01
    • 2015-03-30
    • 1970-01-01
    • 2011-02-24
    • 1970-01-01
    • 1970-01-01
    • 2018-08-16
    相关资源
    最近更新 更多