单例模式是指某些对象保证全局只有一个。
如何在C++中实现具有线程安全的单例模式呢?
下面是一些实现方式:
1 简单的思路 通过类的static方法,定义类的static成员,为了保证线程安全,在进行初始化创建时加锁。
/**
* simple younger
*/
class T {
public:
static T * Instance() {
Lock l;
if (NULL == m_t) {
m_t = new T();
}
return m_t;
}
static void TearDown() {
Lock l;
if (NULL == m_t) {
delete m_t;
}
}
public:
void call() {
cout << "simple younger !" << endl;
}
private:
/**
* operator new been forbbiden
*/
T() {}
T(T &single);
T &operator = (const T & t);
/**
* object forbbiden alloc on stack
*/
~T() {}
private:
static T *m_t;
};
/**类的静态变量需要进行定义*/
T * T::m_t = NULL;
2 可以通过pthead_once来优化加锁,pthead_once保证了初始化的线程安全
class T2 {
public:
static T2 * Instance() {
pthread_once(&mOnce, &T2::init);
return m_t;
}
static void init() {
m_t = new T2();
}
static void TearDown() {
if (NULL != m_t) {
delete m_t;
}
}
public:
void call() {
cout << "simple younger !" << endl;
}
private:
/**
* operator new been forbbiden
*/
T2() {}
T2(T2 &single);
T2 &operator = (const T2 & t);
/**
* object forbbiden alloc on stack
*/
~T2() {}
private:
static T2 *m_t;
static pthread_once_t mOnce;
};
pthread_once_t T2::mOnce = PTHREAD_ONCE_INIT;
T2 *T2::m_t = NULL;
3 c++0x c++11x中 局部静态变量的初始化是线程安全的
另外 g++在变量初始化的过程中,自动加入了锁保证了线程安全
参见:
/**
* arts younger
*/
class A {
public:
static A &Instance() {
/**
* threadsafe in c++ 11x
* 局部静态变量的初始化是线程安全的
*/
static A t;
return t;
}
public:
void call() {
cout << "arts younger !" << endl;
}
private:
/**
* operator new been forbbiden
*/
A() {}
A(const A &);
A &operator = (const A & t);
/**
* object forbbiden alloc on stack
*/
~A() {}
};
4 为了使得更加通用和规范一些,可以先定义一个静态对象,主动调用instance,使得局部变量在被使用之前先被初始化,避免了竞争。
这种实现方式是
BOOST的POOL库的singleton实现。参见:
/**
* 2B younger
*/
class B {
public:
static B *Instance() {
static B b;
return &b;
}
void call() {
cout << "2B younger" << endl;
}
private:
B() {}
B(const B &) {}
B &operator = (const B &);
private:
struct object_creator
{
object_creator() {
B::Instance();
}
};
static object_creator creator_;
};
B::object_creator B::creator_;
注意: 这里如果不使用最后的这个技巧的话,还会有相互调用的竞争问题,即两个单例,如果在一个构造函数中使用另外一个单例的方法,可能会因为这个单例没有被构造而导致非常隐藏的bug,举例如下:
class Fun {
public:
Fun();
static Fun *Instance() {
return &f;
}
~Fun() {
cout << "Fun destruct" << endl;
}
void Call() {
cout << "This is Fun" << endl;
}
private:
static Fun f;
};
Fun Fun::f;
static Tester *Instance() {
return &f;
}
~Tester() {
cout << "Tester destruct" << endl;
}
void Call() {
cout << "This is Tester " << endl;
}
private:
static Tester f;
};
Tester Tester::f;
Fun::Fun()
{
cout << "Fun construct " << endl;
Tester::Instance()->Call();
}
Tester::Tester()
{
cout << "Tester construct " << endl;
/*注意 不能在这里也调用,会导致两个类循环构造
Fun::Instance()->Call();
*/
}
int main()
{
Fun::Instance()->Call();
return 0;
}
运行会输出:
Fun construct
This is Tester
Tester construct
This is Fun
Tester destruct
Fun destruct
可以看到 Tester构造函数执行之前,其方法就会被调用!
最终,定义通用的模板类为:
template <typename T>
class TSingleton {
public:
static T *Instance() {
static T t;
/**
* 确保 creator 编译时被定义
* make sure creator is defined
*/
creator.do_nothing();
return &t;
}
private:
TSingleton<T>() {}
TSingleton<T>(const TSingleton<T> &) {}
TSingleton<T> &operator=(const TSingleton<T> &) {}
~TSingleton<T>() {}
private:
struct object_creator {
object_creator() {
TSingleton<T>::Instance();
}
inline void do_nothing() {}
};
static object_creator creator;
};
template <typename T> typename TSingleton<T>::object_creator TSingleton<T>::creator;
int main()
{
TSingleton<Fun>::Instance()->Call();
return 0;
}
参考: