2012-07-26 206 views
2

我在多线程环境中做了很少的工作。所以,我需要知道下面的类的getInstance函数是否是线程安全的。这里是单例类:单线程线程安全级别

//Singleton class 
class S { 
    // intentionally avoided pointer 
    static S singleObject; 

    // Private constructor 
    s(); 
    s (S &); 
    s& operator= (const s&); 
public: 
    // return reference of static object 
    s& getInstance() 
    { 
    return singleObject; 
    } 

    /* Normally with static pointer instance, getInstnace look like as 
    s& getInstace() 
    { 
     // trying to avoid multiple copies of singleObject 
     lock_mutex() 

     if (singleObject == null) 
      singleObjecct = new S(); 

     unlock_mutex(); 

     return *singleObject; 
    } 
    */ 
}; 

S S::singleObject; 

在getInstance函数(未注释)中,返回静态对象的引用。它是否需要线程安全机制?

在第二个getInstance(注释)中,如果singleObject为null,我们创建该对象。所以,它需要一个锁定机制,需要同步,对吗?

+0

看看http://codereview.stackexchange.com/。 – 2012-07-26 10:00:54

回答

2

在getInstance函数(未注释)中,返回静态对象的引用。它是否需要线程安全机制?

只要你不访问它的main功能的寿命之外,或修改它,当其他线程可能有不同步的访问,那么它的安全地从任何线程访问。

如果在main开始之前或结束之后(例如,从另一个静态对象的构造函数或析构函数中)访问,则存在其未被初始化或已经被销毁的危险那一点。这就是“懒惰初始化”的动机,比如你的第二个版本。

在第二个getInstance(注释)中,如果singleObject为null,我们创建对象。所以,它需要一个锁定机制,需要同步,对吗?

是的,这需要一个锁定机制。对于支持C++ 11(或类似的)线程模型的编译器来说,获得这种懒惰初始化的一种简单方法是使用一个函数静态变量,它将在第一次出现时以线程安全的方式初始化范围:

S& getInstance() 
{ 
    static S singleObject; 
    return singleObject; 
} 

这也将避免您的版本的内存泄漏,但引入了一种危险,即它可能会先于其他静态物体被破坏;因此,从静态对象的析构函数进行访问是不安全的。

一般来说,C++中的静态对象是这样一个死亡陷阱的雷区(无论你是否试图用某种单例反模式包装它们),并且最好避免。

0

IIRC这比这个原因更好。它不会初始化(线程安全),直到调用getInstance。

-edit-我现在记得一些原因。除非调用该方法,否则无法访问。你可以在其他类的构造函数中调用它,并且不必担心S是否已经初始化或者没有。正如在其他类中可能首先构造的那样,在这种情况下会发生崩溃或未定义的行为。

//Singleton class 
class S { 
    // intentionally avoided pointer 

    // Private constructor 
    s(); 
    s (S &); 
    s& operator= (const s&); 
public: 
    // return reference of static object 
    s& getInstance() 
    { 
    static S singleObject; 
    return singleObject; 
    } 
}; 
2

在C++ 11你可以把静态实例静态函数内部:

class S 
{ 
    private: 
     S(); 
     S(S const&); 
     S& operator=(S const&); 

    public: 
     static S& getInstance() 
     { 
      static S singleObject; 
      return singleObject; 
     } 
}; 

按照标准第6.7.4:

零初始化(在所有其他初始化发生之前执行的所有块范围变量(存储持续时间(3.7.1)或线程存储持续时间(3.7.2))为 。常量 具有静态存储的块范围实体的初始化(3.6.2) 持续时间(如果适用)在其块首先输入 之前执行。允许执行初始化其他块范围变量的静态或线程 存储持续时间在相同的条件下,允许在静态或静态初始化变量时使用静态或线程 命名空间范围(3.6。 2)。否则,这种变量 会在控件第一次通过声明时被初始化; 这样的变量在其初始化完成后被认为是初始化的。如果通过抛出异常退出初始化, 的初始化没有完成,所以它会再次尝试下一个 时间控制进入声明。 如果控制在初始化变量时同时输入声明 ,则执行的并发执行应等待初始化完成。如果 控制器在初始化变量 时递归地重新输入声明,则行为未定义。

2

除非将getInstance声明为静态,否则将无法调用它。这个错误几乎已经传播给所有的答复。除此之外,我无法在所有答案中添加更好的东西。