【问题标题】:Why Meyer's Singleton method is not thread-safe?为什么 Meyer 的 Singleton 方法不是线程安全的?
【发布时间】:2021-03-11 11:43:59
【问题描述】:

我从许多讨论中了解到 Meyers Singleton 提供线程安全。为了看到这一点,我用 C++14 编写了一个简单的代码,如下所示。

#include <iostream>
#include <thread>

class SingletonClass {
 public:
       static SingletonClass& Instance() {
           static SingletonClass instance;
           return instance;
       }
       
       void task1() {
           for (int i = 0; i < 50000; ++i)
               a++;
       }
       int getA() {return a;}

   private:
       SingletonClass()= default;
       ~SingletonClass()= default;
       SingletonClass(const SingletonClass&)= delete;
       SingletonClass& operator=(const SingletonClass&)= delete;

       int a;
};

void callSingleton() {
   SingletonClass::Instance().task1();
}

int main() {
   std::thread t1(callSingleton);
   std::thread t2(callSingleton);
   
   t1.join();
   t2.join();

   std::cout << "a: " << SingletonClass::Instance().getA() << std::endl;

   return 0;
}

我希望 a 应该是 100000,因为这个类是线程安全的。但是,我无法为 a 获得 100000 的值。如果 Meyers Singleton 是线程安全的,我不明白为什么这不起作用。提前致谢。

【问题讨论】:

  • 您的 Meyers 单例 访问 是线程安全的。线程不能违反它是单例。但是,检索到的对象不会自动成为线程安全的。

标签: c++ multithreading singleton c++14


【解决方案1】:

因为a 中的数据竞争。

void task1() {
    for (int i = 0; i < 50000; ++i){
        std::lock_guard<std::mutex> lock(mLock);
        a++;
    }
}

或定义

atomic<int> a;

对于两者,我得到 100000。

【讨论】:

  • 感谢您的回复。我同意这些解决方案,我也尝试了它们并获得了 100000。但是,对我来说令人困惑的部分是,如果我不能那样使用这个 Singleton 类的线程安全特性,我该如何使用它。从线程安全来看,我理解多个线程不应该同时修改数据,但在这里我无法理解 Meyers Singleton 的线程安全
  • @finesttea 据我了解,该类删除了复制构造函数和删除了复制赋值,以及私有构造函数。 static SingletonClass instance 确保只创建一个对象并立即返回。如果第一个线程创建了对象,第二个线程只会返回它而不创建新对象。线程安全是指访问对象,而不是类中的成员。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2012-11-20
  • 2013-10-11
  • 2020-10-10
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-08-14
相关资源
最近更新 更多