您的位置:首页 > 编程语言 > C语言/C++

单例模式(对象创建型)c++

2014-02-23 20:59 316 查看
单例模式是:保证一个类仅有一个实例,并提供该一个访问它的全局访问点。

通常可以让一个全局变量是的一个对象被访问,但它不能防止你实例化多个对象。一个好的方法就是,让类自身负责保存它的唯一实例。这个类可以保证没有其他实例被创建(将构造方法定义为私有的或保护的),并且提供一个访问该实例的方法(static方法)。这个实例是类的static变量,对于这个类只有一份。取得实例的方法是静态的,因为构造函数是私有的,所以只能通过类对象直接获得,所以方法也只能定义为静态的。不然无法获得实例。

单例模式最基本的分为两种:饿汉式、懒汉式

饿汉模式是:自己被加载时就将自己实例化。即定义时直接定义为类的一个对象。

另外因为定义的静态变量pInstance是一个指针,可以将一个指向Singleton子类的指针赋给这个变量。

这种是懒汉式单例类:即第一次被引用时,才将自己实例化。即pInstance被初始化为NULL, 而实际初始化是在函数中。懒汉式单例模式存在的问题是,当多线程环境下会出现同步问题,需要控制。

以下为饿汉懒汉实现代码:

////单例模式:保证一个类仅有一个实例,并提供一个访问它的全局访问点
#include <iostream>
using namespace std;

//这种是饿汉式单例模式,即在类被构造出来后就将实例构造出来,
//会提前占用系统资源
class HungrySingleton
{
public:
//这种是饿汉式单例模式,即在类被构造出来后就将实例构造出来,
//会提前占用系统资源
static HungrySingleton *getInstance()
{
return instance;
}
private:
HungrySingleton()
{}
static HungrySingleton* instance;
};
//这里是关键,直接初始化为类的对象,因为是类内数据,所以可以调用构造函数
HungrySingleton* HungrySingleton::instance = new HungrySingleton;

//这种是懒汉式单例模式,即在使用时才将实例构造出来,
//但这个会出现线程同步问题。
class LazySingleton
{
public:
//函数必须是静态的,否则无法访问
static LazySingleton *getInstance()
{
//如果两个线程同时进入getinstance,同时执行,则有两个实例被构造出来
if (instance == NULL)
instance = new LazySingleton();
return instance;
}
private:
//构造函数私有的,不能再外部定义实例
LazySingleton()
{}
static LazySingleton* instance;
};
//初始化为0
LazySingleton* LazySingleton::instance = 0;

int main()
{
HungrySingleton *h1 = HungrySingleton::getInstance();
HungrySingleton *h2 = HungrySingleton::getInstance();

cout << "饿汉式单例模式运行结果:" << endl;
if (h1 == h2)
cout << "是同一个对象" << endl;

LazySingleton *h3 = LazySingleton::getInstance();
LazySingleton *h4 = LazySingleton::getInstance();

cout << "懒汉式单例模式运行结果:" << endl;
if (h3 == h4)
cout << "是同一个对象" << endl;
return 0;
}


为了解决懒汉式的多线程同步问题,加入锁,使用了互斥量,下面是实现代码:

#include <iostream>
#include <pthread.h>
using namespace std;

//解决懒汉式单例模式的多线程同步问题,即在new对象前加上锁,锁的实现在
//linux下采用mutex就够了,因为与顺序无关,只要保证一个时间只有一个线程就行了

class ThreadLazySingleton
{
public:
static ThreadLazySingleton* getInstance(pthread_mutex_t mutex)
{
if (instance == NULL)
{
pthread_mutex_lock(&mutex);
//双重检查,因为如果有两个线程同时通过第一个条件判断,进入到
//内部条件,然后一个线程先申请到互斥量,之后如果为NULL,创建,
//但它退出后,已经分配了一个,所以必须再次重新判断一次是否为
//NULL,否则会再次分配一个对象。
if (instance == NULL)
{
instance = new ThreadLazySingleton;
cout << "getInstance():" << instance << endl;
}
pthread_mutex_unlock(&mutex);
return instance;
}
}
private:
ThreadLazySingleton() {}
static ThreadLazySingleton *instance;
};

ThreadLazySingleton* ThreadLazySingleton::instance = NULL;

void *th_fn1(void *args)
{
cout << "线程" << pthread_self() << "开始运行" << endl;
pthread_mutex_t *mutex = (pthread_mutex_t*)args;
ThreadLazySingleton *p = ThreadLazySingleton::getInstance(*mutex);
cout << p << endl;
pthread_exit((void*)p);
}

int main()
{
pthread_mutex_t mutex;
pthread_mutex_init(&mutex, NULL); //初始化互斥量

int err;
pthread_t tid1, tid2;
ThreadLazySingleton* p1;
ThreadLazySingleton* p2;
err = pthread_create(&tid1, NULL, th_fn1, &mutex);
if (err != 0)
cout << "创建线程" << tid1 << "错误!" << endl;
err = pthread_create(&tid2, NULL, th_fn1, &mutex);
if (err != 0)
cout << "创建线程" << tid2 << "错误!" << endl;
pthread_join(tid1, (void**)&p1);
pthread_join(tid2, (void**)&p2);
//pthread_mutex_destory(&mutex);

if (p1 == p2)
cout << "同一个对象,同步正确" << endl;
cout << p1 <<" " << p2 << endl;
return 0;
}


以上是目前所学到的单例模式的内容。以后会不定时再补充~~
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: