我在多线程环境中做了很少的工作。所以,我需要知道下面的类的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 :(得分: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段:
使用static的所有块范围变量的零初始化(8.5) 存储持续时间(3.7.1)或线程存储持续时间(3.7.2)是 在任何其他初始化发生之前执行。不变 具有静态存储的块范围实体的初始化(3.6.2) 持续时间(如果适用)在其块首次执行之前执行 进入。允许实现尽早执行 使用static或thread初始化其他块作用域变量 在与实现相同的条件下的存储持续时间 允许使用static或thread静态初始化变量 命名空间范围内的存储持续时间(3.6.2)。否则这样的变量 在控制第一次通过其声明时初始化; 这样的变量在完成后被认为是初始化的 初始化。如果通过抛出异常退出初始化, 初始化未完成,因此下次将再次尝试 时间控制进入声明。 如果控制进入声明 在初始化变量的同时,并发 执行应等待初始化完成。如果 控制在变量为的时候递归地重新输入声明 在被初始化时,行为是不确定的。
答案 1 :(得分:2)
在getInstance函数(未注释)中,返回静态对象的引用。它需要线程安全机制吗?
只要您不在main
函数的生命周期内访问它,或者在其他线程可能具有非同步访问权限时修改它,那么从任何线程访问都是安全的。
如果您在main
开始之前或结束之后(例如从另一个静态对象的构造函数或析构函数)访问,那么它就有可能无法初始化,或者已经初始化那时候已经被摧毁了。这是"懒惰初始化的动机"比如你的第二个版本。
在第二个getInstance(注释)中,如果singleObject为null,我们创建对象。所以,它需要一个锁定机制,需要同步,对吗?
是的,这需要一个锁定机制。对于支持C ++ 11(或类似)线程模型的编译器,一种更简单的方法来实现这样的延迟初始化是使用函数静态变量,它将在第一次进入时以线程安全的方式初始化范围:
S& getInstance ()
{
static S singleObject;
return singleObject;
}
这也可以避免你的版本的内存泄漏,但会带来在其他静态对象之前可能被破坏的危险;因此,从静态对象的析构函数访问是不安全的。
一般来说,C ++中的静态对象是这种死亡陷阱的雷区(无论你是否尝试将它们包装成某种单一的反模式),最好避免使用。
答案 2 :(得分:2)
除非您将getInstance声明为静态,否则您将无法调用它。这个错误几乎传播到所有回复。除此之外,我无法为所有答案添加任何更好的内容。
答案 3 :(得分: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;
}
};