单身人士多线程

时间:2010-06-18 11:40:12

标签: c++ multithreading singleton

我有以下课程

class Singleton
{
  private:

    static Singleton *p_inst;
    Singleton();

  public:

    static Singleton * instance()
    {
      if (!p_inst)
      {
        p_inst = new Singleton();
      }

      return p_inst;
    }
};

请详细说明在多线程环境中实施Singleton时采取的预防措施。

6 个答案:

答案 0 :(得分:7)

在多线程条款

if(!p_inst)
{
    p_inst = new Singleton();
}

实际上是3个单独的动作。您获得p_inst的值,设置p_inst的值并写入p_inst的值。因此,get-set-write意味着您需要锁定p_inst,否则您可以拥有2个线程,这些线程创建每个线程使用的Singleton值。

以下是您查看问题的方法,假设您的Singleton有一个可变字段val

thread A -> p_inst is NULL
    thread B -> p_inst is NULL
       thread A -> set to Singleton (1)
           thread B -> set to Singleton (2)
              thread C -> p_inst is Singleton (2)
                  thread A -> set val to 4
                      thread B -> set val to 6
                         thread C -> get val (it's 6)
                             thread A -> get val (it's 4!!)
你知道吗?有一个Singleton浮动的副本,其中两个都不知道另一个。检查Singleton的第三个线程只会看到最后一个分配。但是通过锁定,您可以防止多次分配和这些类型的问题。

答案 1 :(得分:5)

在分配或读取指针之前,你必须使用互斥锁并锁定指针,这使得这个设计模式很慢(而且非常简单)。

答案 2 :(得分:4)

我将简要说明:这取决于你的编译器。

  • 如果您的编译器为本地静态实现多线程同步(即嵌入在方法中的静态实例),则使用它并完成它。
  • 如果没有,Herb Sutter证明这是不可能的。

现在,你必须意识到你可能不需要这个。

有两种方法可以解决这个问题,不需要任何多线程感知。

  1. 只需使用static实例,而不是动态分配它。安全而简单。如果您需要从另一个static变量
  2. 访问初始化顺序,可能会导致初始化顺序问题
  3. 在拥有多个线程之前创建单例实例。通常的诀窍是从main调用它。
  4. 当然,真正的问题是:你不能只是传递对象的引用而不是创建一个全局变量吗?它会使测试变得更容易;)

答案 3 :(得分:4)

您可以通过在启动多个线程之前简单地分配(以任何方式选择)此类对象来消除所有问题。由于设计约束(在静力学中使用单例,你需要延迟分配等),这可能并不总是可行的,但它很简单,并且可以控制创建顺序。有时跟踪有关此类对象分配顺序和时间的问题是一件很容易避免的麻烦。

P.S。 - 我知道这并没有直接回答你的问题,但它可能是一个没有复杂性的真正问题的实际解决方案。

答案 4 :(得分:1)

对于多线程构造,请在instance()函数中使用静态变量。静态变量的初始化由编译器自动保护。任何其他操作都需要显式锁定。使用互斥锁。

class Singleton
{
  private:

    Singleton();

  public:

    static Singleton * instance()
    {
      static Singleton inst;
      return &inst;
    }
};

答案 5 :(得分:1)

你应该问问自己线程安全的意思。

  • 你的单身人员真的需要线程安全吗?

    如果没有,请考虑线程静态方法

  • 您是否希望保证不会创建单身的两个实例?

    如果没有,您的上述解决方案可能没问题,没有任何锁定:您在施工时遇到了竞争条件 - 但是您不关心因为最终只有一个会存活 - 但是,除非您小心,否则您可能会有资源泄漏,这可能会也可能不会很重要。 (这实际上是一个缓存)。

  • 您是否希望保证最终只剩下一个实例?

  • 您是否关心锁定成本?

    如果不是(这很常见),你可以锁定它并开心。

单例是一种可以解决各种问题的模式 - 但是需要什么样的线程安全性与单例模式本身无关,而与你想要的一切有关。